Since Node.js version 7.6, Node.js ships with a new V8 version that features async functions. As Node.js 8 becomes the active LTS version on October 31, there is no reason for not starting to adopt async functions in your codebase. In this article, I will briefly show you what async functions are, and how they change the way we write Node.js applications.
async
async
Promise
async
await
async
Promise
async
Promise
async
The
await
Promise
await
Promise
const rp = require("request-promise");async function main() {const result = await rp("https://google.com");const twenty = await 20;// sleeeeeeeeping for a second 💤await new Promise((resolve) => {setTimeout(resolve, 1000);});return result;}main().then(console.log).catch(console.error);
async
If your Node.js applications are already using
Promise
await
If your applications are built using callbacks, moving to
async
To do so, you can use the built-in
util.promisify
const util = require("util");const { readFile } = require("fs");const readFileAsync = util.promisify(readFile);async function main() {const result = await readFileAsync(".gitignore");return result;}main().then(console.log).catch(console.error);
async
async
express
As
express
async
const express = require("express");const app = express();app.get("/", async (request, response) => {// awaiting Promises here// if you just await a single promise, you could simply return with it,// no need to await for itconst result = await getContent();response.send(result);});app.listen(process.env.PORT);
Edit 1: as Keith Smith pointed out, the above example has a serious issue - if the Promise gets rejected, the
express
To fix this issue, you should wrap your async handlers in a function that handles errors:
const awaitHandlerFactory = (middleware) => {return async (req, res, next) => {try {await middleware(req, res, next);} catch (err) {next(err);}};};// and use it this way:app.get("/",awaitHandlerFactory(async (request, response) => {const result = await getContent();response.send(result);}));
Imagine you are working on something similar, when an operation needs two inputs, one from a database, and one from an external service:
async function main() {const user = await Users.fetch(userId);const product = await Products.fetch(productId);await makePurchase(user, product);}
In this case, what will happen is the following:
user
product
As you can see, you can do the first two in parallel, as they have no dependency on each other. For this, you should use the
Promise.all
async function main() {const [user, product] = await Promise.all([Users.fetch(userId),Products.fetch(productId),]);await makePurchase(user, product);}
In some cases, you only need the result of the fastest resolving Promise - in that cases, you can use the
Promise.race
Consider the following code example:
async function main() {await new Promise((resolve, reject) => {reject(new Error("💥"));});}main().then(console.log);
Once running this snippet, you will get a message in your terminal saying something similar:
(node:69738) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Error: 💥(node:69738) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
In the newer versions of Node.js, if Promise rejections won't be handled, it will bring down the whole Node.js process. Because of this, you should use
try-catch
const util = require("util");async function main() {try {await new Promise((resolve, reject) => {reject(new Error("💥"));});} catch (err) {// handle error case// maybe throwing is okay depending on your use-case}}main().then(console.log).catch(console.error);
However, with
try-catch