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 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
. (从promise返回函数抛出将迫使您同时使用} catch {
和 .catch
。)
People using promisified APIs do not expect promises to throw. (使用承诺的API的人们不会期望诺言。)
If you're not sure how async APIs work in JS - please see this answer first. (如果您不确定JS中异步API的工作方式-请首先查看此答案 。)
1. DOM load or other one time event: (1. DOM加载或其他一次事件:)
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
).
(因此,创建承诺通常意味着指定何时结算-即何时进入承诺阶段或拒绝阶段以指示数据可用(并且可以通过.then
访问)。)
With modern promise implementations that support the Promise
constructor like native ES6 promises:
(使用支持Promise
构造函数的现代Promise
实现(例如本机ES6 Promise
:)
function load() {
return new Promise(function(resolve, reject) {
window.onload = resolve;
});
}
You would then use the resulting promise like so:
(然后,您将使用产生的承诺,如下所示:)
load().then(function() {
// Do things after onload
});
With libraries that support deferred (Let's use $q for this example here, but we'll also use jQuery later):
(使用支持延迟的库(让我们在此示例中使用$ q,但稍后我们还将使用jQuery):)
function load() {
var d = $q.defer();
window.onload = function() { d.resolve(); };
return d.promise;
}
Or with a jQuery like API, hooking on an event happening once:
(或者使用jQuery之类的jQuery,将一次事件挂起:)
function done() {
var d = $.Deferred();
$("#myObject").once("click",function() {
d.resolve();
});
return d.promise();
}
2. Plain callback: (2.普通回调:)
These APIs are rather common since well… callbacks are common in JS.
(这些API相当常见,因为……在JS中回调很常见。)
Let's look at the common case of having onSuccess
and onFail
: (让我们看一下具有onSuccess
和onFail
的常见情况:)
function getUserData(userId, onLoad, onFail) { …
With modern promise implementations that support the Promise
constructor like native ES6 promises:
(使用支持Promise
构造函数的现代Promise
实现(例如本机ES6 Promise
:)
function getUserDataAsync(userId) {
return new Promise(function(resolve, reject) {
getUserData(userId, resolve, reject);
});
}
With libraries that support deferred (Let's use jQuery for this example here, but we've also used $q above):
(使用支持延迟的库(在此示例中,我们使用jQuery,但上面我们也使用$ q):)
function getUserDataAsync(userId) {
var d = $.Deferred();
getUserData(userId, function(res){ d.resolve(res); }, function(err){ d.reject(err); });
return d.promise();
}
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:
(jQuery还提供了$.Deferred(fn)
形式,它的优点是允许我们编写一个非常接近new Promise(fn)
形式的表达式,如下所示:)
function getUserDataAsync(userId) {
return $.Deferred(function(dfrd) {
getUserData(userId, dfrd.resolve, dfrd.reject);
}).promise();
}
Note: Here we exploit the fact that a jQuery deferred's resolve
and reject
methods are "detachable";
(注意:这里我们利用了一个事实,即jQuery deferred的resolve
和reject
方法是“可分离的”。)
ie. (即。)
they are bound to the instance of a jQuery.Deferred(). (它们绑定到jQuery.Deferred()的实例 。)
Not all libs offer this feature. (并非所有库都提供此功能。)
3. Node style callback ("nodeback"): (3.节点样式回调(“ nodeback”):)
Node style callbacks (nodebacks) have a particular format where the callbacks is always the last argument and its first parameter is an error.
(节点样式回调(nodebacks)具有特定的格式,其中回调始终是最后一个参数,而其第一个参数是错误。)
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) reject(err);
else resolve(data);
});
});
}
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 ):
(使用deferred,您可以执行以下操作(尽管本例中Q现在支持您应首选使用的新语法,但让本示例使用Q):)
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;
}
In general, you should not promisify things manually too much, most promise libraries that were designed with Node in mind as well as native promises in Node 8+ have a built in method for promisifying nodebacks.
(通常,您不应该过多地手动分配内容,大多数基于Node设计的Promise库以及Node 8+中的本机Promise具有内置的用于使NodeBback富集的方法。)
For example (例如)
var getStuffAsync = Promise.promisify(getStuff); // Bluebird
var getStuffAsync = Q.denodeify(getStuff); // Q
var getStuffAsync = util.promisify(getStuff); // Native promises, node only
4. A whole library with node style callbacks: (4.带有节点样式回调的整个库:)
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实现允许您批量执行此操作,例如在Bluebird中,将nodeback API转换为promise API很简单:)
Promise.promisifyAll(API);
Or with native promises in Node :
(或在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}), {});
Notes:
(笔记:)
- Of course, when you are in a
.then
handler you do not need to promisify things. (当然,当你在一个.then
处理你不需要promisify事情。)
Returning a promise from a .then
handler will resolve or reject with that promise's value. (从.then
处理程序返回一个诺言将解决或拒绝该诺言的值。)
Throwing from a .then
handler is also good practice and will reject the promise - this is the famous promise throw safety. (从.then
处理程序中抛出也是很好的做法,并且会拒绝诺言-这就是著名的诺言抛出安全性。)
- In an actual
onload
case, you should use addEventListener
rather than onX
. (在实际的onload
情况下,应该使用addEventListener
而不是onX
。)