承诺有状态,它们开始时是待定的,可以结算到:
Promise 返回函数永远不应该抛出,它们应该返回拒绝。从 promise 返回函数抛出将强制您同时使用 a 和 a。使用过期 API 的人不会期望承诺会抛出。如果您不确定异步 API 在 JS 中是如何工作的 , 请先查看此答案。} catch {
.catch
1. DOM 加载或其他一次性事件:
因此,创建承诺通常意味着指定它们何时结算 - 这意味着当它们移动到已履行或拒绝阶段时,以指示数据可用(并且可以访问)。.then
使用支持构造函数的现代承诺实现,如本机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;
}
或者使用像API这样的jQuery,挂接一次发生的事件:
function done() {
var d = $.Deferred();
$("#myObject").once("click",function() {
d.resolve();
});
return d.promise();
}
2. 普通回调:
这些API相当普遍,因为...回调在 JS 中很常见。让我们看一下具有 和 的常见情况:onSuccess
onFail
function getUserData(userId, onLoad, onFail) { …
使用支持构造函数的现代承诺实现,如本机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延迟和方法是“可分离的”这一事实;即。它们绑定到 jQuery.Deferred() 的实例。并非所有库都提供此功能。resolve
reject
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) reject(err);
else resolve(data);
});
});
}
使用延迟,您可以执行以下操作(让我们在此示例中使用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;
}
一般来说,你不应该过多地手动处理事情,大多数在设计时都考虑到了Node的承诺库以及Node 8+中的原生承诺都有一个内置的方法来消除nodebacks。例如
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 中的本机 promise:
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
.then
.then
- 在实际情况下,应使用 而不是 。
onload
addEventListener
onX