Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct way to sequence two asynchronous operations that each return a promise javascript

I was wondering what is the proper way to call a promise after another promise resolves. I know we can use async await to create functions which will resolve a promise. I was wondering which form of handling promises is consider proper practice, or is it good practice to create generators instead? consider the following code:

const fetchSomething = () => new Promise((resolve) => {
  setTimeout(() => resolve(console.log('future value')), 500);
});

const fetchSomethingElse = () => new Promise((resolve) => {
  setTimeout(() => resolve(console.log('future value dueeee')), 3000);
});


const get = () => {
  return fetchSomething().then(function(){
    fetchSomethingElse()
  });
}
get();

or

const fetchSomething = () => new Promise((resolve) => {
  setTimeout(() => resolve({resolve: true}), 500);
});

const fetchSomethingElse = () => new Promise((resolve) => {
  setTimeout(() => resolve({resolve: true}), 3000);
});


const get = async function() {
  const fet = await fetchSomething();
  const fet2 = await fetchSomethingElse();
};

get();
like image 256
hjm Avatar asked Jan 27 '23 15:01

hjm


2 Answers

Either one is fine. Your choice.

In the first you're nesting .then() handlers. In the second, you're using the newer await to sequence them. More people are moving to await because it appears to be simpler code for sequencing operations (assuming you do proper error handling), though in this case, they are pretty similar in complexity, particularly with the simplification suggested below so it's really up to your own personal coding style.

What is missing in both is that get() just returned a promise so you need to use .then() and .catch() with it to get the value and catch any errors.

Also, something that is missing in the first is that you aren't returning the second promise which means the caller won't know when the second operation is done.

Your first can be simplified and fixed up like this:

const get = () => {
  return fetchSomething().then(fetchSomethingElse);
}

get().then(val => {
   // done here
}).catch(err => {
   // error here
});

As Pointy mentioned, you don't "call a promise". You "call a function that returns a promise". Promises are objects. They are not callable.

Probably what your title could be rewritten to is: "Correct way to sequence two asynchronous operations that each return a promise".


For completeness, if your two async operations don't depend upon one another, then you don't have to manually sequence them. You can start them both and then monitor when both are done. This will sometimes get a faster end-to-end response.

You can do that using Promise.all():

const get = function() {
  return Promise.all([fetchSomething(), fetchSomethingElse()]).then(results => {
    // process results array and then return final value
    // results[0] is result from fetchSomething, results[1] is result from fetchSomethingElse
    return finalVal;
  });
}
like image 112
jfriend00 Avatar answered Jan 31 '23 09:01

jfriend00


Both are fine, but you are making a common mistake in the top example (and maybe it's just because of the simplification of the code for the question). You are returning the promise from get, but you are not returning the promise from the then. This means the caller of get won't know when both promises have resolved. Consider:

const fetchSomething = () => new Promise((resolve) => {
  setTimeout(() => resolve(console.log('future value')), 500);
});

const fetchSomethingElse = () => new Promise((resolve) => {
  setTimeout(() => resolve(console.log('future value dueeee')), 3000);
});


const get = () => {
  return fetchSomething().then(function(){
    fetchSomethingElse()
  });
}
// we don't when fetchSomethingElse is done
get().then(() => console.log("done"));
 

Also there's another option you might consider since the second promise doesn't depend on the output of the first. Call them in parallel:

const get = () => {
  return Promise.all([fetchSomething(), fetchSomethingElse() ])
}

In this case one can start before the other is finished and the whole operation should be faster.

like image 36
Mark Avatar answered Jan 31 '23 07:01

Mark