Node.js 8.0.0 から promisify が使えるようになった
Node.js 8.0.0 から util.promisify
が使えるようになった。
これで、外部ライブラリを使わなくても promisify ができる。
const { promisify } = require('util') const { readFile } = require('fs') const readFileAsync = promisify(readFile) async function main () { let buffer = await readFileAsync('hoge.txt') let text = buffer.toString() console.log(text) } main()
Node.js 7 までは、 bluebird
などのライブラリを使って promisify していた。しかも、 async/await
が使えない時代だったら、 co
ライブラリとかで代用していた。
// 昔の書き方 const { promisify } = require('bluebird') const { readFile } = require('fs') const co = require('co') const readFileAsync = promisify(readFile) function main () { return co(function * () { let buffer = yield readFileAsync('hoge.txt') let text = buffer.toString() console.log(text) }) } main()
もうこういう書き方はしなくて済むわけですね。
promisify
は、引数にコールバック関数を渡すような非同期の関数を Promise 化する。
const { promisify } = require('util') function wait (second, callback) { setTimeout(() => { callback() }, 1000 * second) } // Promise 化された関数を返す const waitAsync = promisify(wait) async function main () { console.time('timer') await waitAsync(2) console.timeEnd('timer') } main() // 出力 // timer: 2003.266ms
コールバック関数には規則があって、第一引数は常にエラー扱いになる。
function wait (second, callback) { setTimeout(() => { callback('result') // これだと常にエラーが起きる }, 1000 * second) } const waitAsync = promisify(wait) async function main () { await waitAsync(2) } main() // 出力 // UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): result
何か結果を返したい場合には、コールバック関数の第二引数に与える。
function wait (second, callback) { setTimeout(() => { callback(null, 'result') // 結果を返したい場合にはこう書く }, 1000 * second) }