先日、スクリプト機能がバージョンアップしてNode.jsが8.11.3を選択できるようになりました。この8系以降の特徴として、async/awaitに対応したという点があります。async/awaitはJavaScriptの非同期処理を同期処理のように書ける記法になります。コールバックやPromiseで苦しんだ経験のある方はぜひasync/awaitを使ってみてください。
今回はこのasync/awaitの書き方を解説します。
関数名の頭にasyncを付ける
まずasync/awaitに対応させるために、関数の頭にasyncと書かなければなりません。これは関数、クラスのメソッドでも同じです。
async function Hello() { // 非同期処理 } const Hello = async () => { // 非同期処理 } class Hello { async message() { // 非同期処理 } }
そして、そのasyncと書かれた処理内ではawaitで非同期処理を扱えるようになります。具体的にはPromise処理が対象になります。
const Hello = () => { return new Promise((res, rej) => { return res(); }) } const main = async () => { await Hello(); } main();
なお、Promise処理における失敗時のrejectを呼ぶと、async側ではエラー処理になります。そのため、全体をtry/catchで囲む必要があります。
const main = async () => { try { await Hello(); } catch (err) { // エラー処理 } }
mainのような変数を作るのは面倒なので、無名関数で囲むこともできます。
(async () => { try { await Hello(); } catch (err) { // エラー処理 } })();
コールバックでは使えません
従来のコールバック関数の場合、await/asyncでは使えませんので、Promiseで囲む必要があります。
const fs = require('fs'); const readFile = (path) => { return new Promise((res, rej) => { fs.readFile(path, 'utf-8', (err, data) => { return err ? rej(err) : res(data); }); }) } (async () => { try { const content = await readFile('/tmp/file.txt'); } catch (err) { // エラー処理 } })();
さらにreadFileのような関数を定義するのが面倒な場合は promisify が使えます。これは標準で用意されているユーティリティです。
const fs = require('fs'); const { promisify } = require('util'); (async () => { try { const content = await promisify(fs.readFile)('/tmp/file.txt', 'utf-8'); } catch (err) { // エラー処理 } })();
ループ処理に注意しましょう
async/awaitでのループ処理は推奨されていません。この場合は一旦配列にまとめるのが良いようです。以下は推奨されない方法です。
(async () => { try { const ary = []; for (let i = 0; i < 100; i += 1) { ary.push(await promisify(fs.readFile)(`/tmp/file.${i}.txt`, 'utf-8')); } } catch (err) { // エラー処理 } })();
これを以下のようにします。ただし、個別の処理結果を受けて次の処理に繋ぐ場合など、ループ処理内でawaitを使わざるをえないケースもあるでしょう。
(async () => { try { const promises = []; for (let i = 0; i < 100; i += 1) { promises.push(promisify(fs.readFile)(`/tmp/file.${i}.txt`, 'utf-8')); } // ここでまとめて処理 const ary = await Promise.all(promises); } catch (err) { // エラー処理 } })();
まとめ
async/awaitを使いこなすことで、Promiseでは面倒だった書き方がすっきりします。asyncを忘れるとエラーになったり、awaitを忘れてPromiseで返ってきてしまうこともありますが、それは書いている内に慣れることでしょう。ぜひ積極的に使ってみてください。