mbilyanov
mbilyanov

Reputation: 2511

Clarification regarding promises and async/await needed

I have been using Promises and async/await, they are pretty much the same thing right? Usually what I would do is wrap my promise and return it etc.

function someFetchThatTakesTime(){
    // Promisify the request.
    return new Promise((resolve, reject) => {
        if(allGood){
            resolve();
        }else{
            reject();
    });
}

Then I can do:

someFetchThatTakesTime()
    .then(console.log('all good.')
    .catch(console.log('some error occured.');

or I can do the:

async function wrapMyFetch() {
    try {
        // Make the async call.
        data = await someFetchThatTakesTime();
        return data;
    } catch(err) {
        // Propagate the exception up stream.
        throw err;
    }
}

(async () => {
  let response = await wrapMyFetch();
  // Do stuff with the response.
})();

I guess, pretty clear so far.

However, I have recently encountered situations where my application does not care about waiting for the results to be fetched and the data containers to be updated etc. Let's say there is one larger loop that runs infinitely and any Promised requests simply will fill-in the gaps as the application runs.

In that case, we don't really need the async/await pattern right? We just want to move forward with our loop and stones will fall in place behind us, whenever they are ready to fall in place (or not, in case of an error).

I would like to clarify this: async/await will just force things to run linearly, right? But if we do not want linearity, and we are ok with spawned tasks - Promises - to finish their thing in the background in some time when we are resuming with our run-cycle, we don't need that async/await pattern? Is that correct?

Upvotes: 1

Views: 60

Answers (2)

T.J. Crowder
T.J. Crowder

Reputation: 1074285

async/await will just force things to run linearly, right?

Not globally, no. await makes the code in the async function it's used in wait for the promise you pass it to settle, but that only affects the function you use it in, not anything calling that function.

async functions are syntactic sugar for writing a function that returns a promise. await is syntactic sugar for consuming promises. Together, they dramatically simplify using promises (in particular by making rejections errors that automatically propagate through the call tree).

More specifically, an async function runs its code synchronously until the first await or return (or until code runs off the end of the function), at which point it returns a promise. Its logic then waits for the promise to settle, and continues; eventually it settles its promise based on what happened to the last promise it awaited or returned (or fulfills it with undefined if code execution runs off the end).

If you don't want to wait for a promise to settle, you don't have to, not even in an async function. Just don't use await on it. For instance, assume we have this wrapper for fetch that gets JSON for us (and fixes the API footgun):

async function fetchJSON(...args) {
    const response = await fetch(...args);
    if (!response.ok) {
        throw new Error("HTTP error " + response.status);
    }
    return response.json();
}

Here's an async function using it that does an initial query to get a list of things to fetch, and then fetches all of those things in parallel::

async function fetchList(listUrl) {
    const list = await fetchJSON(listUrl);
    return Promise.all(list.map(item => fetchJSON(itemUrl)));
}

Notice how fetchList uses await to wait for the list of things to fetch, but then doesn't wait for the items; it just returns the promise from Promise.all for the list of items it starts fetching.

Also note how await within fetchJSON makes fetchJSON's logic wait for the fetch promise to settle, but doesn't make the caller calling fetchJSON wait unless that caller uses await. fetchList only awaits the first call (to get the list), it doesn't wait for the item from the list.

Upvotes: 1

jfriend00
jfriend00

Reputation: 707328

I have been using Promises and async/await, they are pretty much the same thing right?

Well, async/await are helpful syntax built on top of promises. Async/await relies on promises in order to work. So, I wouldn't quite call them the same thing, but you can code identically functioning code with await surrounded by try/catch and .then().catch(). You can use either. Both methods rely on promises.

However, I have recently encountered situations where my application does not care about waiting for the results to be fetched and the data containers to be updated etc. Let's say there is one larger loop that runs infinitely and any Promised requests simply will fill-in the gaps as the application runs.

In that case, we don't really need the async/await pattern right? We just want to move forward with our loop and stones will fall in place behind us, whenever they are ready to fall in place (or not, in case of an error).

There is no rule that the caller has to pay attention to a returned promise or has to wait for it before going on with their task. So, if you want to "just let the stones fall as they may in the background" as you say and that's appropriate for your application, you can code that way.

This is often referred to as "fire and forget" coding where you start some asynchronous operation that is going to do something on its own and you don't need to pay attention to when it finishes or if it had an error because that is of no consequence to the calling code.

But, there is a rule that you can't let a promise rejection go unhandled. So, if you're returning a promise and the caller isn't going to do anything with it, then you have to make sure that any rejections are handled by the operation itself (with .catch()) so that the only thing that ever gets returned back is a resolved promise. Even if all you do is notice the error and do nothing with it, you have to catch the error.

Upvotes: 2

Related Questions