jsにおいてコールバック関数は頻出するパターンの一つである。
しかしながら、コールバックヘルという言葉があるとおりネストをすると非常に見づらくなっていく。
本記事では、Node環境においてindex.jsを読み込んで表示するスクリプトを例にいくつかのパターンを見ることにする。
'use strict';
const fs = require('fs');
fs.readFile('index.js', 'utf8', (err, out) => {
if (err) {
console.log(err);
}
console.log(out);
});
Promise化
node v8から導入されたutil.promisify
を使うとコールバックをpromise変換できる。
'use strict';
const {promisify} = require('util');
const fs = require('fs');
promisify(fs.readFile)('./index.js', 'utf-8').then(out => {
console.log(out);
});
async/await
また、v8(ところでv8というとV8(実行エンジン)と区別がつかないことに気づいた)からはasync/awaitが使えるので以下のように書ける。
'use strict';
const { promisify } = require('util');
const fs = require('fs');
async function main() {
const out = await promisify(fs.readFile)('./index.js', 'utf-8');
console.log(out);
}
main();
トップレベルawaitがほしいところではあるが、非同期処理が続くとコールバックより圧倒的に見やすいので積極的に使っていきたい。
pify
しかしながら、これらはv8からでないと使えないので多くの場合、ライブラリで代替することになるだろう。
promise化するライブラリの一つはpify
だ。
$ npm install --save pify
ほぼ、前述したpromisifyと同じように使える。
基本的に自分はこれを使っている。
sindresorhus/pify: Promisify a callback-style function
'use strict';
const fs = require('fs');
const pify = require('pify');
pify(fs.readFile)('./index.js', 'utf-8').then(out => {
console.log(out);
});
非同期?
しかしながら、いつでも非同期が高速ではないことに注意すべきだ。
非同期処理にはオーバヘッドがあり、このようなイベントループをブロックことが問題ではない場合、同期的に書いたほうがはるかに高速に動作する。
'use strict';
const fs = require('fs');
const out = fs.readFileSync('./index.js', 'utf-8');
console.log(out);