Search code examples
httpasync-awaitxmlhttprequestlocal-storagefetch

Synchronous API in the browser containing a HTTP call?


localStorage is synchronous, and if myStore is as well then this will work:

// Example #1
var store = myStore||localStorage;
var item  = store.getItem("data");

However if myStore has an asynchronous element to it it will not work, so to make the code work for both I need to do something like this:

// Example #2
(async () => {
    var store = myStore||localStorage;
    var item  = await store.getItem("data");
})();

(That is, async/await works for both synchronous and asynchronous code).


Now let's say this is my asynchronous code somewhere within myStore:

fetch('http://localhost:3000/getItem', {
        method: 'POST',
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        },
    body: JSON.stringify({ key: key })
});

Or some xhr equivalent.. is it possible to write it as Example #1 somehow, or am I forced to do it like Example #2 if I have a HTTP call anywhere?

Basically I'm trying to implement a localStorage API over HTTP in the browser, and I'd prefer it to behave and be written exactly as the native localStorage API (as far as is possible), and to not have to change localStorage code when introducing myStore other than: myStore||localStorage.


If not possible or recommended, why?


Solution

  • You can only use await inside an async function, and async functions always return a Promise.

    You could think of doing something like this:

    class Store {
      // ...
      async getItem(key){
        return await fetch('http://localhost:3000/getItem', {
          method: 'POST',
          headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({ key: key })
        }).then((res) => res.text());
      }
    }
    

    But the async keyword will force the returned value of getItem to be a promise. So, even if you return a non-promise (in this case, the response text of the request), it will be wrapped in Promise.resolve(), creating a new resolved Promise.

    Therefore, this would not work with the first example because the item variable is supposed to hold some available data, not a Promise.

    So I am afraid you will have to use the second example (which looks appropriate in this case).