简体   繁体   中英

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();

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;
  });
}

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.

It's important to remember that in Promise-based patterns you're using functions that return Promises. Promises are passed in resolve and reject arguments (which are themselves functions). What you resolve with, is what gets exectuted in the .then() phase, and what you reject with gets exectuted in the .catch() phase.

To handle Promises in sequence, you're passing your values into the top-level function that wraps the Promise.

so...

 const p1 = () => { return new Promise((resolve,reject) => { window.setTimeout(() => { resolve('future value one'); },500); }); }; const p2 = (v1) => { return new Promise((resolve,reject) => { window.setTimeout(() => { const v2 = 'future value two'; resolve({v1,v2}); },500); }); }; p1().then(p2).then(console.log); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM