我想使用 util.promisify 来承诺自定义功能。但是, util.promisify 适用于将错误优先回调作为最后一个参数的节点样式方法。如何调整我的自定义函数以便它们与 util.promisify 一起使用?
1 回答
如何调整我的自定义函数以便它们与 util.promisify 一起使用?
我的第一个选择是添加一个返回 Promise 的新 API - 将您自己的 API 包装在一个新的 Promise 构造函数中。然后,您有一个文档化的、返回承诺的 API,该 API 的使用方式很明显,并且客户端不需要额外的步骤即可使用它。
但是,如果你真的想让某些东西与 兼容util.promisify(),请继续阅读......
如果您已经展示了您想要使用的函数的调用约定util.promisify(),我们可以专门为该代码提供自定义实现,但由于您没有在下面提供示例实现。
文档中描述了一般概念,尽管我不会确切地说文档非常清楚事情是如何工作的。这是一个例子。
假设您有一个按以下顺序接收三个参数的计时器函数:
timer(callback, t, v)
其中t是计时器的时间(以毫秒为单位),并且v是计时器触发时它将传递给回调的值。并且,它按该顺序传递回调两个值callback(v, err)。而且,是的,这个特定的计时器有时可以反馈错误。
请注意,特别是回调作为第一个参数传递,而回调本身err作为第二个参数传递,这两者显然与util.promisify()(出于此演示目的)的默认实现不兼容,因为它们与 nodejs 异步调用不匹配惯例。
这是一个不遵循 nodejs 调用约定的计时器(非承诺)函数的示例用法:
// example
timer((v, err) => {
console.log(v, err); // outputs "hi", null
}, 2000, "hi");
为了使其与 兼容util.promisify(),我们可以创建一个自定义的 promisify 行为,如下所示:
// define promise returning implementation of timer that leaves out
// the callback argument, but takes the same other arguments
timer[util.promisify.custom] = (t, v) => {
return new Promise((resolve, reject) => {
timer((value, err) => {
if (err) {
reject(err);
} else {
resolve(value);
}
}, t, v);
});
};
一般概念是,当您将函数引用传递给 时util.promisify(fn),它会查找fn[util.promisify.custom]并且如果存在,它将使用该 promisify 实现而不是其默认实现。如果您想知道它是什么util.promisify.custom,它是库定义的符号util- 只是一个唯一的属性名称,您可以将其作为属性分配给您自己的函数,以识别您已经实现了自定义的 promisify 功能。由于符号在任何 nodejs 实现中都是唯一的,因此将该属性添加到您的函数不会干扰任何其他属性。
然后其他调用者可以像这样使用它:
const timerP = util.promisify(timer);
// you call timerP, leaving out the callback argument
timerP(3000, "bye").then(result => {
console.log(result); // outputs "bye" after 3000ms
}).catch(err => {
console.log(err);
});
如果你想查看 nodejs 的实现util.promisify(),你可以在实际的 util.js代码中看到它。