awaitcauses the function to pause until a Promise is fulfilled or rejected, and to resume execution of the async function after fulfillment. When resumed, the value of the await expression is that of the fulfilled Promise.- If the Promise is rejected, the await expression throws the rejected value.
- If the value of the expression following the await operator is not a Promise, it's converted to a resolved Promise.
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
- https://developers.google.com/web/fundamentals/primers/async-functions
- http://2ality.com/2016/10/async-function-tips.html
example: how to perform some operations in parallel inside async functions, but launch it from inside a non-async function, via Promise.all
// https://stackoverflow.com/questions/42489918/async-await-inside-arraymap
const someFunction = (myArray) => {
const promises = myArray.map(async (myValue) => {
return {
id: "my_id",
myValue: await service.getByValue(myValue)
}
});
return Promise.all(promises);
}
Async functions always return a promise, whether you use await or not. That promise resolves with whatever the async function returns, or rejects with whatever the async function throws. -- https://developers.google.com/web/fundamentals/primers/async-functions
// wait ms milliseconds
function wait(ms) {
return new Promise(r => setTimeout(r, ms));
}
async function hello() {
await wait(500);
return 'world';
}
…calling hello() returns a promise that fulfills with "world".
async function foo() {
await wait(500);
throw Error('bar');
}
…calling foo() returns a promise that rejects with Error('bar').
Promise.resolve/Promise.reject: for use cases that need an already resolved/rejected promise, examples:- make
func1andfunc2happen sequentially:[func1, func2].reduce((p, f) => p.then(f), Promise.resolve());byreduce-ing them to the equivalentPromise.resolve().then(func1).then(func2);- could also be done via a reusable
composeAsyncfunction:let applyAsync = (acc,val) => acc.then(val); let composeAsync = (...funcs) => x => funcs.reduce(applyAsync, Promise.resolve(x)); - ... but the clearest way is to use an
async/awaitequivalent loop:for (let f of [func1, func2]) { await f(); }
- could also be done via a reusable
- make
doSomething().then(successCallback, failureCallback)- guarantees
- callbacks never called before completion of current event loop run
- callbacks added via
then()will still be called, even if they're added after the promise's work (and success/failure "response" to other callbacks added pre-completion) has happened - multiple callbacks can be added by
then()chaining- executed in insertion order
- the return value each
theninvocation is nuanced and highly conditional, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then- for example, if the success/reject handler returns a non-error value,
thenreturns a promise that gets resolved with that value - for example, if the success/reject handler returns a resolved promise,
thenreturns a promise that gets resolved with the value of the promise returned by that handler - etc.
- for example, if the success/reject handler returns a non-error value,
- functions passed to
thenwill never be called synchronously, the current event loop queue will always be drained first, e.g.:Promise.resolve().then(() => console.log(2)); console.log(1); // 1, 2 - only way to communicate an error (to affect the chain) is via
throw(i.e. can't just return anError) catch(failureCallback)is actually just short forthen(null, failureCallback), examples of how that's true in practicethencan be added in a chain after acatch- if an
Erroris thrown from insidecatch, the chain continues as if it was thrown from athenin the same position: an immediately followingthenwill get skipped and a subsequentcatchcan catch thatErrorfrom the earliercatch
example: it's possible to add then() after a catch() in order to have something happen later, regardless of errors
new Promise((resolve, reject) => {
console.log('Initial');
resolve();
})
.then(() => {
throw new Error('Something failed');
console.log('Do this');
})
.catch(() => {
console.log('Do that');
})
.then(() => {
console.log('Do this whatever happened before');
});
// Outputs
Initial
Do that
Do this whatever happened before
doSomething().then(function(result) {
return doSomethingElse(result);
})
.then(function(newResult) {
return doThirdThing(newResult);
})
.then(function(finalResult) {
console.log('Got the final result: ' + finalResult);
})
.catch(failureCallback);
async.series([
function(callback) {
// do some stuff ...
callback(null, 'one');
},
function(callback) {
// do some more stuff ...
callback(null, 'two');
}
],
// optional callback
function(err, results) {
// results is now equal to ['one', 'two']
});
doSomething()
.then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => {
console.log(`Got the final result: ${finalResult}`);
})
.catch(failureCallback);
doSomething(function(result) {
doSomethingElse(result, function(newResult) {
doThirdThing(newResult, function(finalResult) {
console.log('Got the final result: ' + finalResult);
}, failureCallback);
}, failureCallback);
}, failureCallback);
doSomething()
.then(result => doSomethingElse(value))
.then(newResult => doThirdThing(newResult))
.then(finalResult => console.log(`Got the final result: ${finalResult}`))
.catch(failureCallback);
async function foo() {
try {
let result = await doSomething();
let newResult = await doSomethingElse(result);
let finalResult = await doThirdThing(newResult);
console.log(`Got the final result: ${finalResult}`);
} catch(error) {
failureCallback(error);
}
}
- requires the input function to either:
- have a
(err, value)signature - OR have a
util.promisify.customproperty that is a function with a(value)signature and returns aPromise, which covers the case where the target function's signature doesn't align with the required(err, value)format ofutil.promisifyinputs that are functions
- have a
const util = require('util');
function doSomething(foo, callback) {
console.log('doSomething foo:', foo);
callback()
}
doSomething[util.promisify.custom] = function(foo) {
console.log('doSomething[util.promisify.custom] foo:', foo)
return new Promise(function(resolve, reject) {
doSomething(foo, resolve, reject);
});
};
const promisified = util.promisify(doSomething);
async function callit() {
await promisified('abc')
console.log('after await');
}
(async () => {
await callit()
console.log('after callit');
})();