Dr. Greg Bernstein
Updated October 19th, 2021
async function declarationFrom MDN async function
An asynchronous function is a function which operates asynchronously via the event loop, using an implicit Promise to return its result.
Example:
function square(x){return x*x}
async function asquare(x){return x*x}
Using async functions:
// regular function returns a value
console.log(square(8));
// async function returns a promise
asquare(8).then(y => console.log(y));
Why bother?
await operatorFrom MDN await
The await operator is used to wait for a Promise. It can only be used inside an async function.
[rv] = await expression;await Example 1
function square(x){return x*x}
async function asquare(x){return x*x}
async function test() {
p1 = new Promise(function(resolve, reject){
setTimeout(()=>resolve("Hi Class!"), 1000);
});
let x = await square(9); // wait for a value
let y = await asquare(10); // wait for async fuction
console.log(`x= ${x}, y=${y}, at ${new Date()}`);
let msg = await p1; // wait for a promise
console.log(`message = ${msg}, at ${new Date()}`);
}
console.log(`Starting test at ${new Date()}`);
test();
console.log(`Finished calling test`);
await Example 1 ContinuedKey takeaways:
Inside an async function we can use await to wait for promises to resolve and get their value.
test() itself has to be an async function so we can use await in it.
test() returns a promise and hence is run via the event loop.
Ordered time consuming operations are much easier to think about and program with async/await.
function square(x){return x*x}
async function asquare(x){return x*x}
async function test() {
p1 = new Promise(function(resolve, reject){
setTimeout(()=>reject("Surprise Class!"), 2000);
});
let x = await square(9); // wait for a value
let y = await asquare(10); // wait for async fuction
console.log(`x= ${x}, y=${y}, at ${new Date()}`);
let msg = await p1; // wait for a promise
console.log(`message = ${msg}, at ${new Date()}`);
}
console.log(`Starting reject test at ${new Date()}`);
test();
console.log(`Finished calling reject test`);
function square(x){return x*x}
async function asquare(x){return x*x}
async function test() {
try {
p1 = new Promise(function(resolve, reject){
setTimeout(()=>reject("Surprise Class!"), 2000);
});
let x = await square(9); // wait for a value
let y = await asquare(10); // wait for async fuction
console.log(`x= ${x}, y=${y}, at ${new Date()}`);
let msg = await p1; // wait for a promise
console.log(`message = ${msg}, at ${new Date()}`);
} catch (e) {
console.log(`exception: ${e}`);
}
}
console.log(`Starting reject test 2 at ${new Date()}`);
test();
console.log(`Finished calling reject test 2`);
async/await exception handlingInside async functions when we use await we can deal with Promise rejection via the usual try/catch exception handling mechanisms!
async/await ExamplesLet’s try throwing around a promise goodTimePromise.js
myTime = 0.0;
startTime = new Date();
function oneSecond() { // Returns a promise that resolves in one second
return new Promise(function(resolve, reject){
setTimeout(()=>resolve(), 1000);
});
}
function advanceTime() {
myTime += 1.0;
elapsedTime = (new Date() - startTime)/1000.0;
console.log(`myTime = ${myTime}, elapsedTime = ${elapsedTime}`);
return oneSecond(); // Returns another new one second promise
}
// What will this do?
oneSecond()
.then(advanceTime)
.then(advanceTime)
.then(advanceTime);
async/awaitFile: goodTimeAsync.js in the AsyncExamples.zip
let myTime = 0.0;
let startTime = new Date();
function oneSecond() {
// Returns a promise that resolves in one second
return new Promise(function(resolve, reject) {
setTimeout(() => resolve(), 1000);
});
}
function advanceTime() {
myTime += 1.0;
elapsedTime = (new Date() - startTime) / 1000.0;
console.log(`myTime = ${myTime}, elapsedTime = ${elapsedTime}`);
}
async function myTimer(n) {
for (let i = 0; i < n; i++) {
await oneSecond();
advanceTime()
}
}
myTimer(5); // Set number to count to whatever you like.
File: threeInOrder.mjs in NodeRequests.zip
import fetch from 'node-fetch';
let site1 = {
url: "https://www.grotto-networking.com",
options: {method: "HEAD"}
};
let site2 = {
url: "http://www.google.com",
options: {method: "HEAD"}
};
let site3 = {
url: "https://kitewest.com.au/",
options: {method: "HEAD"}
};
let start = new Date();
fetch(site1.url, site1.options)
.then(res => {
// console.log(`Grotto status: ${JSON.stringify(res)}`);
let time = (new Date() - start) / 1000;
console.log(`Grotto status: ${res.statusText}, time: ${time}`);
return fetch(site2.url, site2.options);
})
.then(res => {
let time = (new Date() - start) / 1000;
console.log(`Google status: ${res.statusText}, time: ${time}`);
return fetch(site3.url, site3.options);
})
.then(res => {
let time = (new Date() - start) / 1000;
console.log(`Aus kiteboarding status: ${res.statusText}, time: ${time}`);
});
console.log("Starting my web requests:");
async/awaitFrom threeInOrderAsync.mjs in NodeRequests.zip
/* Demonstration of promises to put HTTP requests for
Node.js in a particular order with async and await!
*/
import fetch from 'node-fetch';
let site1 = {
url: "https://www.grotto-networking.com",
options: { method: "HEAD" }
};
let site2 = {
url: "http://www.google.com",
options: { method: "HEAD" }
};
let site3 = {
url: "https://kitewest.com.au/",
options: { method: "HEAD" }
};
let start = new Date();
async function inOrder() {
let res = await fetch(site1.url, site1.options);
let time = (new Date() - start) / 1000;
console.log(`Grotto status: ${res.statusText}, time: ${time}`);
res = await fetch(site2.url, site2.options);
time = (new Date() - start) / 1000;
console.log(`Google status: ${res.statusText}, time: ${time}`);
res = await fetch(site3.url, site3.options);
time = (new Date() - start) / 1000;
console.log(`Aus kiteboarding status: ${res.statusText}, time: ${time}`);
}
console.log("Starting my web requests:");
inOrder();
Here we are collecting sailing logs from the web such as: https://windsurf.grotto-networking.com/data/logs/windEvents2019.json. There are ten years of logs from 2009 to 2019.
Each log has between 40 and 80 samples (sailing sessions)
We want to start with the current year and go back in time till we have enough samples to do some statistics. We don’t know how many files we will need to recover ahead of time.
Uses recursion and side effects. It is also hard to read. SailingCountRecursive.mjs
import fetch from 'node-fetch';
var totalCount = 0;
var year = 2021;
var desiredCount = 200;
function logAdd(year, data) {
console.log(`Year ${year}, sailing sessions = ${data.length}`);
totalCount += data.length;
if (totalCount < desiredCount) {
let url = 'https://windsurf.grotto-networking.com/data/logs/windEvents' + (year - 1) + '.json';
fetch(url).then(res => res.json()).then(logAdd.bind(null, year - 1));
}
}
let url1 = 'https://windsurf.grotto-networking.com/data/logs/windEvents' + year + '.json';
fetch(url1).then(res => res.json()).then(logAdd.bind(null, year));
Come up with a clean non-recursive Promise based implementation!
async/await versionFile sailingCount.mjs in NodeRequests.zip
/* Demonstration of Promises and async/await to
visit an indeterminant number of data sources one at a time
until a criteria is reached.
*/
import fetch = from 'node-fetch';
let desiredCount = 150; // How many years do we have to go back to reach this
async function getThem(year) {
let totalCount = 0;
let curYear = year; // Start here and work backwards
while (totalCount < desiredCount) {
let url = 'https://windsurf.grotto-networking.com/data/logs/windEvents' + curYear + '.json';
totalCount += await fetch(url)
.then(res => res.json())
.then(data => data.length);
console.log(curYear, totalCount);
curYear -= 1;
}
}
getThem(2021);
async/await doesn’t replace Promises, but uses Promises
async/await much easier for in-order type operations, these come up both on the server-side and the client-side.
We will still want to use Promises directly particularly in very simple cases and in cases that require parallel operations such as Promise.all() and Promise.race()
Remember that Promises and async/await are mechanisms for asynchronous programing provided by JavaScript. Other languages and environments may have more or less mechanisms to support asynchronous operations.