javascript - 如何将现有的回调 API 转换为 Promise?

标签 javascript node.js callback promise bluebird

我想使用 Promise,但我有一个回调 API,格式如下:

1. DOM 加载或其他一次性事件:

window.onload; // set to callback
...
window.onload = function() {

};

2. 普通回调:
function request(onChangeHandler) {
    ...
}
request(function() {
    // change happened
    ...
});

3. Node 样式回调(“nodeback”):
function getStuff(dat, callback) {
    ...
}
getStuff("dataParam", function(err, data) {
    ...
})

4.带有 Node 样式回调的整个库:
API;
API.one(function(err, data) {
    API.two(function(err, data2) {
        API.three(function(err, data3) {
            ...
        });
    });
});

我如何在 promise 中使用 API,我如何“ promise ”它?

最佳答案

Promise 具有状态,它们以待处理状态开始,并且可以解决:

  • 已完成表示计算成功完成。
  • 拒绝表示计算失败。

  • Promise 返回函数 should never throw ,他们应该返回拒绝。从 promise 返回函数中抛出将迫使您同时使用 } catch {.catch .使用 Promisified API 的人并不期望 Promise 会抛出。如果你不确定异步 API 在 JS 中是如何工作的 - 请 see this answer第一的。

    1. DOM 加载或其他一次性事件:

    因此,创建 Promise 通常意味着指定它们何时结算 - 这意味着它们何时移动到已完成或已拒绝阶段以指示数据可用(并且可以通过 .then 访问)。

    使用支持 Promise 的现代 promise 实现原生 ES6 之类的构造函数 promise :
    function load() {
        return new Promise(function(resolve, reject) {
            window.onload = resolve;
        });
    }
    

    然后,您将像这样使用生成的 promise :
    load().then(function() {
        // Do things after onload
    });
    

    使用支持延迟的库(我们在此示例中使用 $q,但稍后我们还将使用 jQuery):
    function load() {
        var d = $q.defer();
        window.onload = function() { d.resolve(); };
        return d.promise;
    }
    

    或者使用类似 jQuery 的 API, Hook 一次发生的事件:
    function done() {
        var d = $.Deferred();
        $("#myObject").once("click",function() {
            d.resolve();
        });
        return d.promise();
    }
    

    2. 普通回调:

    这些 API 相当普遍,因为……回调在 JS 中很常见。让我们看一下拥有 onSuccess 的常见情况。和 onFail :
    function getUserData(userId, onLoad, onFail) { …
    

    使用支持 Promise 的现代 promise 实现原生 ES6 之类的构造函数 promise :
    function getUserDataAsync(userId) {
        return new Promise(function(resolve, reject) {
            getUserData(userId, resolve, reject);
        });
    }
    

    使用支持延迟的库(我们在此示例中使用 jQuery,但我们在上面也使用了 $q):
    function getUserDataAsync(userId) {
        var d = $.Deferred();
        getUserData(userId, function(res){ d.resolve(res); }, function(err){ d.reject(err); });
        return d.promise();
    }
    

    jQuery 还提供了 $.Deferred(fn)形式,它的优点是允许我们编写一个非常接近 new Promise(fn) 的表达式。形式,如下:
    function getUserDataAsync(userId) {
        return $.Deferred(function(dfrd) {
            getUserData(userId, dfrd.resolve, dfrd.reject);
        }).promise();
    }
    

    注意:这里我们利用了 jQuery 延迟的 resolve 的事实。和 reject方法是“可拆卸的”; IE。它们绑定(bind)到 jQuery.Deferred() 的实例。并非所有库都提供此功能。

    3. Node 样式回调(“nodeback”):

    Node 样式回调(nodebacks)具有特定格式,其中回调始终是最后一个参数,其第一个参数是错误。让我们首先手动 promise 一个:
    getStuff("dataParam", function(err, data) { …
    

    到:
    function getStuffAsync(param) {
        return new Promise(function(resolve, reject) {
            getStuff(param, function(err, data) {
                if (err !== null) reject(err);
                else resolve(data);
            });
        });
    }
    

    使用 deferreds 您可以执行以下操作(让我们在此示例中使用 Q,尽管 Q 现在支持新语法 which you should prefer ):
    function getStuffAsync(param) {
        var d = Q.defer();
        getStuff(param, function(err, data) {
            if (err !== null) d.reject(err);
            else d.resolve(data);
        });
        return d.promise;   
    }
    

    一般来说,您不应该过多地手动 promise 事情,大多数在设计时考虑到 Node 的 promise 库以及 Node 8+ 中的 native promise 都有一个用于 promise nodebacks 的内置方法。例如
    var getStuffAsync = Promise.promisify(getStuff); // Bluebird
    var getStuffAsync = Q.denodeify(getStuff); // Q
    var getStuffAsync = util.promisify(getStuff); // Native promises, node only
    

    4.带有 Node 样式回调的整个库:

    这里没有金科 Jade 律,你一一答应他们。但是,一些 Promise 实现允许您批量执行此操作,例如在 Bluebird 中,将 nodeback API 转换为 Promise API 非常简单:
    Promise.promisifyAll(API);
    

    或者使用 中的原生 promise Node :
    const { promisify } = require('util');
    const promiseAPI = Object.entries(API).map(([key, v]) => ({key, fn: promisify(v)}))
                             .reduce((o, p) => Object.assign(o, {[p.key]: p.fn}), {});
    

    笔记:
  • 当然,当你在 .then处理程序你不需要 promise 事情。从 .then 返回一个 promise 处理程序将使用该 promise 的值解决或拒绝。从 .then throw handler 也是一种很好的做法,并且会拒绝 promise - 这是著名的 promise 抛出安全。
  • 在实际 onload情况下,您应该使用 addEventListener而不是 onX .
  • 关于javascript - 如何将现有的回调 API 转换为 Promise?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55128506/

    相关文章:

    javascript - Chrome 上的 jQuery fontSize 增加

    javascript - Jquery 对话框模式问题

    javascript - 调用在 setInterval 中定义的匿名函数

    javascript - 让 webfontloader 与 node.js 和 jsdom 一起工作

    jquery - MathJax:尝试重新呈现数学时无法从给定数据进行回调

    javascript - 如何删除 Ext JS 中的禁用属性

    node.js - 为什么我们在 nodejs 中使用导出?

    node.js - 在服务器之间扩展 socket.io

    opengl - 如何精细控制过剩内循环

    C 将结构传递给回调函数 (Tizen)