使用 util.promisify 承诺自定义函数

Promisifying custom functions with util.promisify

我想使用 util.promisify 来承诺自定义函数。但是,util.promisify 适用于将错误优先回调作为最后一个参数的节点样式方法。我如何调整我的自定义函数,以便它们可以与 util.promisify 一起使用?

How can I adjust my custom functions so that they will work with util.promisify?

我的第一选择是添加一个新的 API,returns 一个承诺 - 将您自己的 API 包装在一个新的 Promise 构造函数中。然后,您就有了一个文档化的、返回承诺的 API,它的使用方法很明显,客户不需要额外的步骤就可以使用它。

但是,如果您真的想制作与 util.promisify() 兼容的东西,请继续阅读...

如果您已经显示了您希望 util.promisify() 使用的函数的调用约定,我们可以专门为该代码提供自定义实现,但由于您没有,下面是一个示例实现.

文档中描述了一般概念 here,但我不会确切地说文档非常清楚事情是如何工作的。这是一个例子。

假设您有一个计时器函数,它按以下顺序接受三个参数:

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);
});

如果你想看到 util.promisify() 的 nodejs 实现,你可以在实际 util.js code.

中看到它