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/await
File: 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/await
From 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.