如何将现有的回调API转换为承诺?

我想使用承诺,但我有一个格式的回调API:

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

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

};

2.普通回调:

function request(onChangeHandler){
    ...
}
request(function(){
    // change happened
    ...
});

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

function getStuff(dat,callback){
    ...
}
getStuff("dataParam",function(err,data){
    ...
})

4.具有节点样式回调的整个库:

API;
API.one(function(err,data){
    API.two(function(err,data2){
        API.three(function(err,data3){
            ...
        });
    });
});

我如何在承诺中使用API​​,如何“promisify”它?


承诺有国家,他们开始等待,并可以解决:

  • 满足这意味着计算成功完成。
  • 被拒绝的意思是计算失败。
  • 承诺返回函数不应该抛出,他们应该返回拒绝。 从promise返回函数抛出将迫使你使用} catch {.catch 。 使用promisified APIs的人不会期望承诺会抛出。 如果你不确定异步API如何在JS中工作 - 请首先看到这个答案。

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

    因此,创建承诺一般意味着指定何时他们解决 - 这意味着当他们转移到履行或拒绝阶段,以表明数据可用(并可以通过.then访问)。

    使用支持Promise构造函数(如本地ES6)的现代承诺实现承诺:

    function load(){
        return new Promise(function(resolve,reject){
             window.onload = resolve;
        });
    }
    

    然后,您会使用如此产生的承诺:

    load().then(function(){
        // Do things after onload
    });
    

    使用支持延迟的库(让我们在这里使用$ q作为示例,但我们也将在以后使用jQuery):

    function load(){
        var d = $q.defer();
        window.onload = function(){ d.resolve(); };
        return d.promise;
    }
    

    或者使用类似API的jQuery,可以连接一次发生的事件:

    function done(){
        var d = $.Deferred();
        $("#myObject").once("click",function(){
             d.resolve();
        });
        return d.promise();
    }
    

    2.普通回调:

    这些API很常见,因为...回调在JS中很常见。 让我们看看有onSuccessonFail的常见情况:

     function getUserData(userId, onLoad, onFail){ ...
    

    使用支持Promise构造函数(如本地ES6)的现代承诺实现承诺:

    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延迟的resolvereject方法是“可拆卸”的事实; 即。 它们绑定到jQuery.Deferred()的实例。 并非所有库都提供此功能。

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

    节点样式回调(nodebacks)具有特殊的格式,其中回调总是最后一个参数,其第一个参数是错误。 我们先手动提示一个:

    getStuff("dataParam",function(err,data){
    

    至:

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

    使用延迟你可以做以下事情(让我们用Q代表这个例子,尽管Q现在支持你应该更喜欢的新语法):

    function getStuffAsync(param){
        var d = Q.defer();
        getStuff(param,function(err,data){
             if(err !== null) return d.reject(err); // `throw err` also works here.
                 d.resolve(data);
        });
        return d.promise;   
    }
    

    一般来说,你不应该过多地手动提供这些东西,大多数承诺在Node中设计的库以及Node 8+中的本地promise都有一个内置的方法来提升nodeback。 例如

    var getStuffAsync = Promise.promisify(getStuff); // Bluebird
    var getStuffAsync = Q.denodeify(getStuff); // Q
    var getStuffAsync = util.promisify(getStuff); // Native promises, node only
    

    4.具有节点样式回调的整个库:

    这里没有黄金法则,你们一个一个的让步。 但是,有些承诺实现允许您批量执行此操作,例如在Bluebird中,将nodeback API转换为承诺API非常简单:

    Promise.promisifyAll(API);
    

    或者在Node中使用本地承诺:

    const promiseAPI = Object.keys(API).map(key => {key, fn: util.promisify(API[key]))
                            .reduce((o, p) => Object.assign(o, {[p.key] : p.fn}), {});
    

    笔记:

  • 当然,当你在一个.then处理你不需要promisify事情。 然后从一个处理者那里返回一个承诺.then将会解决或拒绝承诺的价值。 从投掷.then处理也是很好的做法,将拒绝承诺-这就是著名的承诺抛安全。
  • 在实际的onload情况下,您应该使用addEventListener而不是onX

  • 今天,我可以在Node.js使用Promise作为一个简单的Javascript方法。

    Promise一个简单而基本的例子(用KISS方式):

    Javascript Javascript异步API代码:

    function divisionAPI (number, divider, successCallback, errorCallback) {
    
        if (divider == 0) {
            return errorCallback( new Error("Division by zero") )
        }
    
        successCallback( number / divider )
    
    }
    

    Promise Javascript异步API代码:

    function divisionAPI (number, divider) {
    
        return new Promise(function (fulfilled, rejected) {
    
            if (divider == 0) {
                return rejected( new Error("Division by zero") )
            }
    
            fulfilled( number / divider )
    
         })
    
    }
    

    (我建议访问这个美丽的来源)

    Promise可以搭配在一起asyncawaitES7使程序流程等待一个fullfiled类似如下的结果:

    function getName () {
    
        return new Promise(function (fulfilled, rejected) {
    
            var name = "John Doe";
    
            // wait 3000 milliseconds before calling fulfilled() method
            setTimeout ( 
                function() {
                    fulfilled( name )
                }, 
                3000
            )
    
        })
    
    }
    
    
    async function foo () {
    
        var name = await getName(); // awaits for a fulfilled result!
    
        console.log(name); // the console writes "John Doe" after 3000 milliseconds
    
    }
    
    
    foo() // calling the foo() method to run the code
    

    使用.then()方法使用相同代码的另一种用法

    function getName () {
    
        return new Promise(function (fulfilled, rejected) {
    
            var name = "John Doe";
    
            // wait 3000 milliseconds before calling fulfilled() method
            setTimeout ( 
                function() {
                    fulfilled( name )
                }, 
                3000
            )
    
        })
    
    }
    
    
    // the console writes "John Doe" after 3000 milliseconds
    getName().then(function(name){ console.log(name) })
    

    Promise也可以用于任何基于Node.js的平台,如react-native

    希望这可以帮助。


    我不认为@Benjamin的window.onload建议会一直工作,因为它不检测它是否在加载后调用。 我被这么多次咬了。 这是一个应该始终工作的版本:

    function promiseDOMready() {
        return new Promise(function(resolve) {
            if (document.readyState === "complete") return resolve();
            document.addEventListener("DOMContentLoaded", resolve);
        });
    }
    promiseDOMready().then(initOnLoad);
    
    链接地址: http://www.djcxy.com/p/1627.html

    上一篇: How do I convert an existing callback API to promises?

    下一篇: Aren't promises just callbacks?