利用 Node.js 的 promisify 将回调转 Promise
利用 Node.js 的 promisify 将回调转 Promise
Node.js 中存在大量回调形式的 API,虽然后续的版本中大部分已经对应提供了 Promise 版本。
通过 util.promisify
可将回调形式的 API 转 promise。
以 fs.stat 为例,下面是来自官方文档中的演示:
const util = require("util");
const fs = require("fs");
const stat = util.promisify(fs.stat);
stat(".")
.then((stats) => {
// Do something with `stats`
})
.catch((error) => {
// Handle the error.
});
转 promise 的条件
util.promisify
假定被转函数最后一个参数为 Node.js 中错误优先的回调形式,即,最后一个入参长这样 (err, value) => ...
。
Node.js 的 API 大多遵循这种风格,所以这样的假设能满足大部分场景,但不是全部。
自定义 Promise 化的函数
不满足的情况下可通过自定义的试来操作。
具体来说,假如被转函数身上存在一个名叫 util.promisify.custom
的属性,调用 promisify
后会返回该属性的值。
例如,被转函数为
const original = (arg1, arg2,...)=> ...
同时 original[util.promisify.custom]
存在,那么:
original[util.promisify.custom] === util.promisify(original);
上面的操作有什么用?
这个 util.promisify.custom
是 Node.js 提供的符号,作为名称在这里使用而以,没什么特别。
假设有如下回调形式的函数:
function doSomething(data, onSuccessCallback, onErrorCallback)
通过自定义 promisify 的返回,将其转成 Promise 调用。
doSomething[util.promisify.custom] = (foo) => {
return new Promise((resolve, reject) => {
doSomething(foo, resolve, reject);
});
};
const promisified = util.promisify(doSomething);
promisified(foo)
.then(()=>console.log('success))
.catch((err) => console.log(err));
更加 General 的情况
推而广之,如果不考虑错误处理,函数第一个参数是不是错误就无所谓了,任何回调形式都可以改成 Promsie,比如 setTimeout。
const { promisify } = require("util");
const sleep = promisify(setTimeout);
const main = async () => {
console.time("sleep");
await sleep(1000);
console.timeEnd("sleep");
};
main();
像上面,我们压根就不关心调用 setTimeout 之后的返回,因此就不涉及它内部的流程处理,直接利用了其 Promise 特性而以。