如何将现有的回调API转换为promise?
我想使用promises,但我有一个回调API格式如:
I want to work with promises but I have a callback API in a format like:
window.onload; // set to callback
...
window.onload = function(){
};
2。纯回调:
2. Plain callback:
function request(onChangeHandler){
...
request(function(){
// change happened
});
3。节点样式回调(nodeback):
3. Node style callback ("nodeback"):
function getStuff(dat,callback){
...
getStuff("dataParam",function(err,data){
}
4。具有节点样式回调的整个库:
4. A whole library with node style callbacks:
API;
API.one(function(err,data){
API.two(function(err,data2){
API.three(function(err,data3){
})
});
});
如何在promise中使用API, promisifyit?
承诺有状态,它们开始作为待处理,可以结算:
Promises have state, they start as pending and can settle to:
- 已履行,表示计算已成功完成。
- fulfilled meaning that the computation completed successfully.
- rejected meaning that the computation failed.
允许返回函数不应该抛出,它们应该返回拒绝promise返回函数将强制您同时使用} catch {
和 a .catch
。使用promisified API的人不希望promise抛出。如果您不确定JS中的异步API是如何工作的,请首先查看此答案。
Promise returning functions should never throw, they should return rejections instead. Throwing from a promise returning function will force you to use both a } catch {
and a .catch
. People using promisified APIs do not expect promises to throw. If you're not sure how async APIs work in JS - please see this answer first.
因此,创建promise通常意味着指定何时结算 - 这意味着当他们移动到已完成或已拒绝阶段以指示数据可以使用 .then
)访问。
So, creating promises generally means specifying when they settle - that means when they move to the fulfilled or rejected phase to indicate the data is available (and can be accessed with .then
).
c> Promise 构造函数,如原生ES6 promises:
With modern promise implementations that support the Promise
constructor like native ES6 promises:
function load(){
return new Promise(function(resolve,reject){
window.onload = resolve;
});
}
使用支持deferred的库(让我们在这里使用$ q,我们也将使用jQuery):
With libraries that support deferred (Let's use $q for this example here, but we'll also use jQuery later):
function load(){
var d = $q.defer();
window.onload = function(){ d.resolve(); };
return d.promise;
}
或者使用jQuery类API,挂钩事件发生一次: p>
Or with a jQuery like API, hooking on an event happening once:
function done(){
var d = $.Deferred();
$("#myObject").once("click",function(){
d.resolve();
});
return d.promise();
}
2。平原回调:
这些API是很常见的,因为...回调在JS中很常见。让我们看看 onSuccess
和 onFail
的常见情况:
function getUserData(userId, onLoad, onFail){ ...
$ b b
现代promise实现支持 Promise
构造函数,如原生ES6 promises:
With modern promise implementations that support the Promise
constructor like native ES6 promises:
function getUserDataAsync(userId){
return new Promise(function(resolve,reject){
getUserData(userId,resolve,reject);
});
}
使用支持deferred的库(让我们在这里使用jQuery, 've也使用$ q上面):
With libraries that support deferred (Let's use jQuery for this example here, but we've also used $q above):
function getUserDataAsync(userId){
var d = $.Deferred();
getUserData(userId,function(res){ d.resolve(res); } ,function(err){ d.reject(err); });
return d.promise();
}
jQuery还提供 $。Deferred
表单,其优点是允许我们编写一个非常接近新Promise(fn)
表单的表达式,如下所示:
jQuery also offers a $.Deferred(fn)
form, which has the advantage of allowing us to write an expression that emulates very closely the new Promise(fn)
form, as follows:
function getUserDataAsync(userId) {
return $.Deferred(function(dfrd) {
getUserData(userId, dfrd.resolve, dfrd.reject);
}).promise();
}
注意:这里我们利用一个事实,一个jQuery deferred的 resolve
和 reject
方法是可分离的;即。它们绑定到jQuery.Deferred()的实例。并非所有的库都提供此功能。
Note: Here we exploit the fact that a jQuery deferred's resolve
and reject
methods are "detachable"; ie. they are bound to the instance of a jQuery.Deferred(). Not all libs offer this feature.
节点样式回调(nodebacks)具有特定格式,其中回调始终是最后一个参数,其第一个参数是错误。让我们先手动进行promisify:
Node style callbacks (nodebacks) have a particular format where the callbacks is always the last argument and its first parameter is an error. Let's first promisify one manually:
getStuff("dataParam",function(err,data){
To:
function getStuffAsync(param){
return new Promise(function(resolve,reject){
getStuff(param,function(err,data){
if(err !== null) return reject(err);
resolve(data);
});
});
}
$ b有了延迟,你可以做以下(让我们使用Q这个例子,虽然Q现在支持你应该喜欢的新语法):
With deferreds you can do the following (let's use Q for this example, although Q now supports the new syntax which you should prefer):
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的库有一个内置的方法来承诺nodeback。例如
In general, you should not promisify things manually too much, most promise libraries that were designed with Node in mind have a built in method for promisifying nodebacks. For example
var getStuffAsync = Promise.promisify(getStuff); // Bluebird
var getStuffAsync = Q.denodeify(getStuff); // Q
4。具有节点样式回调的整个库:
这里没有黄金规则,你一个一个地承诺它们。然而,一些promise实现允许你这样做批量,例如在蓝鸟,将nodeback API转换为promise API是简单的:
4. A whole library with node style callbacks:
There is no golden rule here, you promisify them one by one. However, some promise implementations allow you to do this in bulk, for example in Bluebird, converting a nodeback API to a promise API is as simple as:
Promise.promisifyAll(API);
注意:
- 当然,当你在
.then
处理程序中时,你不需要承诺。从.then
处理程序返回一个promise将解析或拒绝该promise的值。从.then
处理程序抛出也是好的做法,并将拒绝承诺 - 这是着名的承诺抛出安全。 - 在实际
onload
中,您应该使用addEventListener
code> onX 。
- Of course, when you are in a
.then
handler you do not need to promisify things. Returning a promise from a.then
handler will resolve or reject with that promise's value. Throwing from a.then
handler is also good practice and will reject the promise - this is the famous promise throw safety. - In an actual
onload
case, you should useaddEventListener
rather thanonX
.