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

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

一,。DOM加载或其他一次性事件:

window.onload;//设置为回调
...
window.onload=函数(){
};

二,。普通回调:

函数请求(onChangeHandler){

}
请求(函数(){
//发生了变化

});

三,。节点样式回调(“节点回退”):

函数getStuff(dat,回调){

}
getStuff(“数据参数”,函数(错误,数据){

})

四,。具有节点样式回调的整个库:

API;
API.one(函数(错误、数据){
API.2(函数(错误,数据2){
API.3(函数(错误,数据3){
...
});
});
});

如何在promises中使用API,如何“承诺”它

承诺有状态,开始时是待定的,可以解决以下问题:

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

承诺返回函数不应抛出,而应返回拒绝。从承诺返回函数中抛出将迫使您同时使用}catch{a.catch。使用promisified API的人不希望承诺抛出。如果您不确定异步API在JS中如何工作,请先查看此答案

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

因此,创建承诺通常意味着指定它们何时结算,也就是说当它们移动到完成或拒绝阶段时,表明数据可用(并且可以通过访问。然后

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

函数加载(){
返回新承诺(功能(解决、拒绝){
window.onload=解析;
});
}

然后,您将使用这样的结果承诺:

load()。然后(函数(){
//加载后做事情
});

对于支持deferred的库(在这里我们使用$q作为示例,但稍后我们也将使用jQuery):

函数加载(){
var d=$q.defer();
window.onload=function(){d.resolve();};
回报承诺;
}

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

函数完成(){
var d=$.Deferred();
$(“#myObject”)。一次(“单击”,函数(){
d、 解决();
});
返回d.promise();
}

2.普通回调:

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

函数getUserData(userId,onLoad,onFail){…

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

函数getUserDataAsync(userId){
返回新承诺(功能(解决、拒绝){
getUserData(用户ID、解析、拒绝);
});
}

对于支持deferred的库(让我们在这里使用jQuery作为示例,但我们也使用了上面的$q):

函数getUserDataAsync(userId){
var d=$.Deferred();
getUserData(userId,函数(res){d.resolve(res);},函数(err){d.reject(err);});
返回d.promise();
}

jQuery还提供了一个$.Deferred(fn)表单,它的优点是允许我们编写一个非常接近新承诺(fn)表单的表达式,如下所示:

函数getUserDataAsync(userId){
返回延迟的美元(函数(dfrd){
getUserData(userId,dfrd.resolve,dfrd.reject);
}).promise();
}

注意:这里我们利用了一个事实,即jQuery deferred的解析拒绝方法是“可分离的”;也就是说,它们绑定到jQuery.deferred()的实例。并非所有lib都提供此功能

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

节点样式回调(Nodeback)具有特定的格式,其中回调始终是最后一个参数,其第一个参数是错误。让我们首先手动提示一个:

getStuff(“dataParam”,函数(err,data){…

致:

函数getStuffAsync(param){
返回新承诺(功能(解决、拒绝){
getStuff(参数,函数(错误,数据){
如果(错误!==null)拒绝(错误);
else解析(数据);
});
});
}

对于延迟,您可以执行以下操作(在本例中使用Q,尽管Q现在支持您更喜欢的新语法):

函数getStuffAsync(param){
var d=Q.defer();
getStuff(参数,函数(错误,数据){
如果(err!==null)d.拒绝(err);
否则d.解析(数据);
});
回报承诺;
}

一般来说,您不应该过多地手动实现承诺,大多数在设计时考虑到节点以及Node 8+中的本机承诺的承诺库都有一个内置的方法来实现节点回退

var getStuffAsync=Promise.promisify(getStuff);//蓝鸟
var getStuffAsync=Q.denodeify(getStuff);//Q
var getStuffAsync=util.promisify(getStuff);//本机承诺,仅限节点

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

这里没有黄金法则,你可以一个接一个地承诺。但是,一些promise实现允许你批量这样做,例如在Bluebird中,将nodeback API转换为promise API非常简单:

promisifyAll(API);

或者在节点中使用本机承诺

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

注:

  • 当然,当你在处理程序中时,你不需要承诺任何事情。从返回承诺。然后处理程序将根据承诺的价值来解决或拒绝。从处理程序抛出也是一个好的实践,并且会拒绝承诺-这就是著名的承诺抛出安全
  • 在实际的onload情况下,应该使用addEventListener而不是onX

发表评论