Nodejs 8 有一个新的工具函数 util.promisify()。他将一个接收回调函数参数的函数转换成一个返回Promise的函数。
1、util.promisify()小例子
// echo.js const {promisify} = require('util'); const fs = require('fs'); const readFileAsync = promisify(fs.readFile); // (A) const filePath = process.argv[2]; readFileAsync(filePath,{encoding: 'utf8'}) .then((text) => { console.log('CONTENT:',text); }) .catch((err) => { console.log('ERROR:',err); });
注意:在第一行,程序使用promisify()
转换基于回调函数的方法fs.readFile()
成一个返回promise
的一个函数
$ node echo.js echo.js CONTENT: const {promisify} = require('util'); ··· $ node echo.js unkNown.txt ERROR: { Error: ENOENT: no such file or directory,··· }
2、使用async
函数
// echoa.js const {promisify} = require('util'); const fs = require('fs'); const readFileAsync = promisify(fs.readFile); const filePath = process.argv[2]; async function main() { try { const text = await readFileAsync(filePath,{encoding: 'utf8'}); console.log('CONTENT:',text); } catch (err) { console.log('ERROR:',err); } } main();
3、转换有多个参数的回调函数为Promise
下面的函数的回调函数接收多于一个的参数(除了error参数)
child_process.exec
child_process.execFile
dns.lookup
dns.lookupService
fs.read
fs.write
如果你转换这些函数为promise,它会返回一个对象(由多个参数组成的对象,而不是一个值)。例如,dns.lookup
的回调函数包含下面几个参数
err : Error
address : string
family : integer
转换成Promise之后,它的参数将会变成{address,family}
这样一个对象
const util = require('util'); const dns = require('dns'); const lookupAsync = util.promisify(dns.lookup); lookupAsync('nodejs.org') .then(obj => console.log(obj)); // { address: '104.20.23.46',family: 4 }
promisify()
通过内部符号internal/util/customPromisifyArgs
处理非标准回调函数。因此不推荐传入一个非标准的回调函数,也不应该去转换我们自己实现的回调(ps:自己就直接写Promise就好了。。。)
4、定制的Promise函数
promisified
的API来源于util.promisify.custom
,它允许您将一个promisified
版本附加到一个基于回调的函数。 在以下示例中,fooAsync
是foo
的promisified
版本
const util = require('util'); function foo() { return 'abc'; } async function fooAsync() { return 'abc'; } foo[util.promisify.custom] = fooAsync; console.log(util.promisify(foo) === fooAsync); // true
4.1 定制了promisified
版本的标准函数
现在,有两个标准函数有定制的promisified
版本
> setImmediate[util.promisify.custom] [Function] > setTimeout[util.promisify.custom] [Function]
5、低版本node兼容库
Jordan Harband写了一个库a polyfill for util.promisify(),用来兼容promisify,使用方法如下
需要注意:
安装
npm install util.promisify
使用方式有两种
第一种,检查是否有内置实现(Node 8)或者使用 polyfill (旧的Node版本)
const promisify = require('util.promisify'); const fs = require('fs'); const readFileAsync = promisify(fs.readFile);
第二种,在旧版本的Node上使用补丁模块
const util = require('util'); require('util.promisify').shim(); const fs = require('fs'); const readFileAsync = util.promisify(fs.readFile);