Promises
Promises are used to wait for data, then act on it. Otherwise JS will just continue running your code as it is non-blocking.
Standard non-blocking function
Without prompises and async / await, the following code will print:
End of long task
Complete end
End of timeout
function doALongTask() {
// wait 1 seconds to simulate a slow operation
setTimeout(() => {
console.log("End of timeout");
}, 1000);
console.log("End of long task");
};
doALongTask();
console.log('Complete end');
Async function with promise
The code will now print the following. complete end is non blocking, so prints immediately. end of long task and end of timeout are inside of an async function, which automatically returns a promise. This promise then uses the await keyword to wait for the timeout function to resolve, which it does after the timeout. The end long task then executes.
Complete end
End of timeout
End of long task
// async function with long op wrapped in a promise
async function doSomeLongTask() {
await new Promise((resolve) => { // waits for resolve before returning to other code
// wait 2 seconds to simulate a slow operation
setTimeout(() => {
console.log("End of timeout");
resolve(); // calls resolve
}, 2000);
});
console.log("End of long task");
}
doSomeLongTask(); // waits for the long task function, then displays 1 and 2
console.log('Complete end'); // This is outside the function, so js runs this while the long
Then-Catch
Promises can also return data (resolve-return), which can then be processed succinctly. If an error is encountered in the async function, it is caught later in the .catch() call.
// waits for resolve before returning value to caller
async function doThenLongTask() {
let cntr = 5;
await new Promise((resolve) => {
// wait 2 seconds to simulate a slow operation
setTimeout(() => {
cntr++
resolve();
//throw new Error("BLAH!!!!");
}, 2000);
});
return cntr;
};
doThenLongTask()
.then((data) => {
return data + 4;
})
// subsequent data operations can be performed
.then((data) => {
console.log(data);
})
.catch(function (error) {
console.log('Oops!', error);
});
Async functions
Some functions are already aysnc, like fetch.
// do an async call to a jokes API, then wait to print the response.
fetch('https://icanhazdadjoke.com/', {
headers: {
"User-Agent": "node",
"Accept": "application/json"
}
})
.then(res => res.json())
.then(res => {
console.log(res.joke)
})
.catch((error) => {
console.log('ERROR:', error);
});
Incompatibilities
For-each is not compatible with async. Everthing will run non-blocking in for-each. Use for-of instead. Eg:
const myArray = [1,2,3,4,5,6,7,8,9];
async function processArrayAsync(arr) {
// arr.forEach(async (item) => { // does not support async operations
for(const item of arr) {
await someAsyncOperation(item);
console.log(`Processed: ${item}`);
};
}
function someAsyncOperation(item) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
},parseInt(item) * 500);
});
}
processArrayAsync(myArray)
.then(() => {
console.log('All items processed');
})
.catch((error) => {
console.log(`Error: ${error}`);
});
Output
Processed: 1
Processed: 2
Processed: 3
Processed: 4
Processed: 5
Processed: 6
Processed: 7
Processed: 8
Processed: 9
All items processed
Parallel and wait for all
Wait for all async functions to complete before returning
async function processParallel() {
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve) => {
setTimeout(resolve,4000, 'foo');
});
Promise.all([promise1,promise2,promise3])
.then((values) => {
console.log(values);
});
}
processParallel();