Asynchronous Programming in JS
Promises
Promises can be in the following states:
- fullfilled
- rejected
- pending
How to create promise:
const myPromise = new Promise((resolve, reject) => {
if (condition) {
resolve('Stuff worked');
} else {
reject("Error, it's broken");
}
});
myPromise
.then(result => console.log(result))
.catch(err => console.log('Error: ', err));
Merge Promises
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'Message 1');
});
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'Message 2');
});
const promise4 = new Promise((resolve, reject) => {
setTimeout(resolve, 3000, 'Message 3');
});
Promise.all([promise2, promise3, promise4]).then((result) =>
console.log('Result', result)
);
The result
is an array of messages.
ES8 - Async/Await
It’s just a syntax sugar over promises.
Example of code with promises:
movePlayer(100, 'Left')
.then(() => movePlayer(200, 'Right'))
.then(() => movePlayer(300, 'Left'))
.then(() => movePlayer(150, 'Left'));
This could be transformed into async
function the following way:
async function playerStart() {
const firstMove = await movePlayer(100, 'Left');
await movePlayer(200, 'Right');
await movePlayer(300, 'Left');
await movePlayer(150, 'Left');
}
It make the code easier to read.
There is more realistic with error handling:
const urls = [
'https://random-data-api.com/api/address/random_address',
'https://random-data-api.com/api/app/random_app',
'https://random-data-api.com/api/business_credit_card/random_card',
];
// Promise.all(urls.map((u) => fetch(u).then((resp) => resp.json())))
// .then(([address, app, card]) => console.log(address, app, card))
// .catch((err) => console.log('Error: ', err));
const getData = async function () {
try {
const [address, app, card] = await Promise.all(
urls.map((u) => fetch(u).then((resp) => resp.json()))
);
console.log(address, app, card);
} catch (err) {
console.log('Error', err);
}
};
getData();
ES9 (ES2018) Async
finally
myPromise
.then(result => console.log(result))
.catch(err => console.log('Error: ', err))
.finally(() => ...);
for await of
const getData = async function () {
const arrayOfPromises = urls.map((url) => fetch(url));
for await (let request of arrayOfPromises) {
const data = await request.json();
console.log('ASD', data);
}
};
getData();
Job Queue
Consider the following code:
setTimeout(() => console.log('Message 1'), 0);
setTimeout(() => console.log('Message 2'), 10);
Promise.resolve('hi').then((e) => console.log('Message 3'));
console.log('Message 4');
Console log result is the following:
Message 4
Message 3
Message 1
Message 2
The reason is that Promises is a part of JS. It’s work using Job Queue, or Microtask Queue. This queue has a higher priority than the Callback queue.
Parallel, Sequence and Race
Sequence is just a set of await
. Race is a Promise.race([...])
. And finally parallel is a Promise.all([...])
ES2020 allSettled
Promise.allSettled([promise2, promise3, promise4]).then((result) =>
console.log('Result', result)
);
It will return an array with items, each of them has a status
(fullfilled
| rejected
) & value
or reason
fields.
ES2021 contains also Promise.any([])
method, which will return only those results, which is fullfilled.