util
util
util是 Node 提供的内置对象,提供一些常用的帮助函数。
util.promisify()
Node 8 提供了util.promisify方法,用于将那些接受回调函数的函数,转变为 Promise。
举例来说,fs.readFile()是一个接受回调函数的方法,用法如下。
fs.readFile('path/to/file', 'utf8', (err, data) => {
// ...
});
上面代码中,fs.readFile的第一个参数path/to/file和第二个参数utf8是运行所需要的,第三个参数是一个回调函数。该函数的参数符合 Node 的惯例,分别是运行中的错误err和运行结果data。
util.promisify可以将这个方法转为 Promise。转化后的参数就是fs.readFile的前两个参数。一旦 Promise 成功,就会传回data,否则传回err。
const {promisify} = require('util');
const fs = require('fs');
const readFileAsync = promisify(fs.readFile);
const filePath = process.argv[2];
readFileAsync(filePath, 'utf8')
.then((text) => {
console.log('CONTENT:', text);
})
.catch((err) => {
console.log('ERROR:', err);
});
将上面的代码存为echo.js,用法如下。
$ node echo.js echo.js
CONTENT: const {promisify} = require('util');
···
$ node echo.js unknown.txt
ERROR: { Error: ENOENT: no such file or directory, ··· }
由于util.promisify返回的函数,执行后会返回 Promise,所以可以用于async...await语法。
async function main() {
try {
const text = await readFileAsync(filePath, {encoding: 'utf8'});
console.log('CONTENT:', text);
} catch (err) {
console.log('ERROR:', err);
}
}
main();
有些异步方法会向回调函数提供多于一个的参数,比如dns.lookup()。
dns.lookup('nodejs.org', function (err, address, family) {
// ...
});
上面代码中,dns.lookup的第二个参数是一个回调函数,它接受三个参数:err、address、family。
util.promisify转变dns.lookup后,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 }
如果一个函数具有util.promisify.custom属性,那么util.promisify会返回该属性指向的函数。
const util = require('util');
function foo() {
return 'abc';
}
async function fooAsync() {
return 'abc';
}
foo[util.promisify.custom] = fooAsync;
util.promisify(foo) === fooAsync // true
上面代码中,foo函数的util.promisify.custom属性指向fooAsync,所以util.promisify(foo)会返回fooAsync。
目前,有两个内置函数部署了util.promisify.custom属性。
setImmediate[util.promisify.custom]setTimeout[util.promisify.custom]
之所以是这两个函数,因为它们的回调函数位置是不规则的,都是参数列表的第一位。
setImmediate(callback, ...args);
setTimeout(callback, delay, ...args);
util.promisify封装它们的例子如下。
const {promisify} = require('util');
const delay = promisify(setTimeout);
delay(3000).then(() => console.log('done'));
参考链接
- Node.js 8: util.promisify(), by Axel Rauschmayer