在nodejs裡,大部分的io相關function是async,async透過callback返回處理結果, 因此在流程處理上容易因為連續多個async造成callback hell, 有些方式可以減緩這樣的問題:例如
- async套件(https://www.npmjs.com/package/async),
- ES2015的promise
- ES2017的async await
都是處理這類的問題(async await在nodejs 7.6+支援)。 而promise和async await又能夠很好的配合使用。透過async await能夠大幅地消除callback hell, 並且很接近synchronous call的編寫流程。
但大多數的nodejs io function都是callback style的,無法直接被async await利用。 在nodejs8中有提供一個util function: util.promisify 能夠將callback style function轉成promise
var util = require('util'); var fs = require('fs'); var fswriteFile = util.promisify(fs.writeFile); <strong>async </strong>function main(){ try{ <strong>await </strong>fswriteFile('test.txt', 'hello world'); //await promise console.log('write successfully'); //上面的promise resolve後才會走到這一行 }catch(e){ console.log(e); } } main();
util.promisify使用時對於大部分callback style function FUNC(arg1, arg2, arg3…, callback) 不需特別注意,但少數callback參數不是在最後一個,則可以透過指定util.promisify.custom 告訴util.promisify要使用特定的promise
事實上可參考 setTimeout, setImmediate
{ [Function: setTimeout] [Symbol(util.promisify.custom)]: [Function] }
以下給出一個範例
var util = require('util'); function setTimeout1(ms){ return new Promise(function(resolve, reject){ setTimeout0(resolve, ms); }); } function setTimeout0(callback, ms){ setTimeout(callback, ms); } setTimeout0[util.promisify.custom] = setTimeout1; var setTimeoutP = util.promisify(setTimeout0); console.log(setTimeoutP == setTimeout1);
對於像dns.lookup在callback中有多個value回傳的,nodejs也定義了customPromisifyArgs,使得promise回傳會將多個值以object key value型式返回