嗯,这是关于承诺解决方案的来源。 Q 和许多其他库提供了两个 API:
-
旧版
defer API - 您可以在其中创建一个可以.resolve(value) 的延迟,并且它有一个可以返回的承诺。
-
Promise 构造函数 - 这是现代 API,您可以在其中从完成源创建 Promise。
大致做:
var d = Q.defer();
setTimeout(function(){ d.resolve(); }, 1000);
return d.promise;
等同于:
return new Promise(function(resolve, reject){
setTimeout(resolve, 1000);
});
所以你可能会问
为什么我们需要两个 API?
好吧,defer API 是第一位的。这是其他一些语言如何处理它,这是论文如何处理它以及人们如何首先使用它 - 然而 - 这两个 API 之间存在重要差异。 Promise 构造函数是安全的。
投掷安全
承诺抽象异常处理并且是抛出安全的。如果你抛出一个承诺链,它会将该异常转换为拒绝,引用规范:
如果 onFulfilled 或 onRejected 抛出异常 e,则 promise2 必须以 e 为理由被拒绝
假设您正在从 XHR 请求中解析 JSON:
function get(){
var d = Q.defer();
if(cached) { // use cached version user edited in localStorage
d.resolve(JSON.parse(cached));
} else { // get from server
myCallbackApi('/foo', function(res){ d.resolve(res); });
}
}
现在,让我们看看 Promise 构造函数的版本:
function get(){
return new Promise(function(resolve, reject){
if(cached) { // use cached version user edited in localStorage
resolve(JSON.parse(cached));
} else { // get from server
myCallbackApi('/foo', resolve);
}
});
}
现在,假设您的服务器以某种方式向您发送了无效的 JSON(或用户将其编辑为无效状态)并且您缓存了它。
在延迟版本中 - 它同步抛出。因此,您通常必须防范它。在底层版本中它没有。顶级版本用法如下所示:
try{
return get().catch(function(e){
return handleException(e); // can also just pass as function
});
} catch(e){
handleException(e);
}
在底层版本中——promise 构造函数会将throws 转换为拒绝,所以这样做就足够了:
return get().then(function(e){
return handleException(e);
});
防止发生一整类程序员错误。