Asynchronous - more than one code thread can be run at the same time.
Synchronous - (default) code runs as one thread and one command has to finish before the next
one can start.
...you can also take a look at an MDN document on
async/await
(Making asynchronous programming easier with async and await).
...and also another
document on (Choosing the right approach).
The async keyword is used to write functions that handle asynchronous actions.
We wrap our asynchronous logic inside a function prepended with the async keyword.
Then, we invoke that function. Eg...
async function myFunc() {
// Function body here
};
myFunc();
OR you can say...
const myFunc = async () => {
// Function body here
};
myFunc();
async functions always return a promise.
This means we can use traditional promise syntax, like .then() and .catch()
with our async functions.
An async function will return in one of three ways:-
...If there’s nothing returned from the function, it will return a promise
with a resolved value of undefined.
...If there’s a non-promise value returned from the function, it will return a
promise resolved to that value.
...If a promise is returned from the function, it will simply return that promise.
For example...
async function fivePromise() { return 5; } fivePromise() .then(resolvedValue => { console.log(resolvedValue); }) // Prints 5In the example above, even though we return 5 inside the function body, what’s actually returned when we invoke fivePromise() is a promise with a resolved value of 5.
Therefore, a promise that may be written like...
function nativePromise(){ return new Promise((resolve, reject) => { resolve('yay!'); }) }Using async could be written like...
async function asyncPromise(){ return 'yay!'; }Because
function withConstructor(num){ return new Promise((resolve, reject) => { if (num === 0){ resolve('zero'); } else { resolve('not zero'); } }); } async function withAsync(num) { return withConstructor(num); }; withAsync(100) .then((resolveValue) => { console.log(` withAsync(100) returned: ${resolveValue}.`); }) >//would print to the Console.log... //withAsync(100) returned: not zero. withAsync(0) .then((resolveValue) => { console.log(` withAsync(0) returned: ${resolveValue}.`); }) //would print to the Console.log... //withAsync(100) returned: zero.
async functions are almost always used with the additional keyword await inside
the function body.
The await keyword can only be used inside an async function.
await is an operator: it returns the resolved value of a promise.
Since promises resolve in an indeterminate amount of time, await halts, or pauses, the
execution of our async function until a given promise is resolved.
So, for example...
Lets pretend we have a promise function (let's call it 'funcTakesTime()') that runs a
few .then() commands that prints out messages as it goes
and could take a bit of time to run.
And we call it in our async function...
async function myAsync() {
let myTask = await
funcTakesTime();
console.log(`All tasks have finished now.`);
}
When run this would display...
funcTakesTime Message 1
funcTakesTime Message 2
funcTakesTime Message 3
etc...
All tasks have finished now.
Because the await command will make everything stop until all
the funcTakesTime tasks
have completed (it makes it run synchronously).
But if we do NOT have the await command then the result would be...
All tasks have finished now.
funcTakesTime Message 1
funcTakesTime Message 2
funcTakesTime Message 3
etc...
Because the removal of the await command will make everything run
asynchronously and not wait for the other funcTakesTime tasks to
complete first.
This file is called library.js and it exports its functions
for use by the file app.js
const shopForBeans = () => { return new Promise((resolve, reject) => { const beanTypes = ['kidney', 'fava', 'pinto', 'black', 'garbanzo']; setTimeout(()=>{ let randomIndex = Math.floor(Math.random() * 5); let beanType = beanTypes[randomIndex]; console.log(`I bought ${beanType} beans because they were on sale.`); resolve(beanType); }, 1000) }) } let soakTheBeans = (beanType) => { return new Promise((resolve, reject) => { console.log('Time to soak the beans.'); setTimeout(()=>{ console.log(`... The ${beanType} beans are softened.`); resolve(true); }, 1000); }); } let cookTheBeans = (isSoftened) => { return new Promise((resolve, reject) => { console.log('Time to cook the beans.'); setTimeout(()=>{ if (isSoftened) { console.log('... The beans are cooked!'); resolve('\n\nDinner is served!'); } }, 1000); }); } module.exports = { shopForBeans, soakTheBeans, cookTheBeans};
This file is called app.js and it imports its functions
from the file library.js
const {shopForBeans, soakTheBeans, cookTheBeans} = require('./library.js'); async function makeBeans() { let type = await shopForBeans(); let isSoft = await soakTheBeans(type); let dinner = await cookTheBeans(isSoft); console.log(dinner); } makeBeans();The line (above)
The above is an example of a routine that is expected to complete successfully all the time.
But seeing as not everything does always work, the below example allows for something to fail.
With this I have used the
Try/Catch routine (the link will take you to my page on Try/Catch if you want to see
that as well.
This file is called library.js and it exports its functions
for use by the file app.js
// This function returns true 50% of the time. let randomSuccess = () => { let num = Math.random(); if (num < .5 ){ return true; } else { return false; } }; // This function returns a promise that // resolves half of the time and // rejects half of the time. let cookBeanSouffle = () => { return new Promise((resolve, reject) => { console.log('Fingers crossed... Putting the Bean Souffle in the oven'); setTimeout(()=>{ let success = randomSuccess(); // Remember to use RESOLVE and REJECT when // trying to catch errors. if(success){ resolve('Bean Souffle'); } else { reject('Dinner is ruined!'); } }, 1000); }); }; module.exports = cookBeanSouffle;
This file is called app.js and it imports its functions
from the file library.js
const cookBeanSouffle = require('./library.js'); async function hostDinnerParty() { try { //lets call our routine let dinnerMsg = await cookBeanSouffle(); //If it RESOLVED okay then 'dinnerMsg will // = 'Bean Souffle' // But if it REJECTED then it will // drop to the 'catch (error)' area // and the 'error' variable will // = 'Dinner is ruined' //If it RESOLVED then //NOTE // when using ${..} to display a variable // you MUST use `` (before the 1 key) // and NOT "" or '' console.log(`${dinnerMsg} is served!`); } catch (error){ console.log(error); console.log("Ordering a pizza!"); } } hostDinnerParty();The first message displayed on the console.log will always be
Normally I would use...eg...
async function serveDinner() { const vegetablePromise = await steamBroccoli(); const starchPromise = await cookRice(); const proteinPromise = await bakeChicken(); const sidePromise = await cookBeans(); console.log(`Dinner is served. We're having ${vegetablePromise}, ${starchPromise}, ${proteinPromise}, and ${sidePromise}.`); }But you could also do it like this...
async function serveDinner() { const vegetablePromise = steamBroccoli(); const starchPromise = cookRice(); const proteinPromise = bakeChicken(); const sidePromise = cookBeans(); console.log(`Dinner is served. We're having ${await vegetablePromise}, ${await starchPromise}, ${await proteinPromise}, and ${await sidePromise}.`); }Because the const vegetablePromise = steamBroccoli();