使用 Promises 时,为什么不能在代码库的其他位置定义
resolve
和 reject
的触发器?
我不明白为什么
resolve
和 reject
逻辑应该本地化在声明承诺的地方。这是一个疏忽,还是强制使用 executor
参数有好处吗?
我认为执行器函数应该是可选的,并且它的存在应该决定承诺是否封装解析。如果没有这样的强制要求,承诺将具有更大的可扩展性,因为您不必立即启动异步。承诺也应该是可重置的。这是一个单次开关,1 或 0,
resolve()
或 reject()
。可以附加多种并行和顺序结果:promise.then(parallel1)
和promise.then(parallel2)
以及promise.then(seq1).then(seq2)
,但有参考权限的玩家无法解析/拒绝进入切换
您可以稍后构建结果树,但您无法更改它们,也无法更改根(输入触发器)
老实说,顺序结果树也应该是可编辑的……假设在声明了许多承诺链之后,您想拼接一个步骤并做其他事情。重建承诺和每个顺序函数是没有意义的,特别是因为你甚至无法拒绝或销毁承诺......
这被称为 Domenic 创造的揭示构造函数模式。
基本上,这个想法是让您在该对象尚未完全构造时访问该对象的“部分”。引用多梅尼克的话:
我将其称为揭示构造函数模式,因为 Promise 构造函数揭示了其内部功能,但仅限于构造相关 Promise 的代码。解决或拒绝 Promise 的能力仅向构建代码透露,并且至关重要的是,不会向使用 Promise 的任何人透露。因此,如果我们将 p 交给另一个消费者,比如过去
$q
、Q、jQuery 和旧版本的 bluebird 中,这仍然是正确的(但经常被弃用)。
API 类似于:
var d = Deferred();
d.resolve();
d.reject();
d.promise; // the actual promise
它有效,但有一个问题。 Deferreds 和 Promise 构造函数通常用于将非 Promise API 转换为 Promise。 JavaScript 中有一个“著名”问题,称为Zalgo
- 基本上,这意味着 API 必须是同步或异步的,但不能同时两者兼而有之。 问题是 - 通过延迟,可以做类似的事情:
function request(param) {
var d = Deferred();
var options = JSON.parse(param);
d.ajax(function(err, value) {
if(err) d.reject(err);
else d.resolve(value);
});
}
这里有一个隐藏的微妙错误 - 如果
param
不是有效的 JSON,该函数会同步抛出
,这意味着我必须将每个承诺返回函数包装在
} catch (e) {
和 .catch(e =>
中以捕获所有错误.
Promise 构造函数捕获此类异常并将其转换为拒绝,这意味着您永远不必担心同步异常与带有 Promise 的异步异常。 (它通过始终在“下一个刻度”执行
then
回调来保护您)。
此外,它还需要一个额外的类型,每个开发人员都必须了解 Promise 构造函数不知道的地方,这非常好。
仅供参考,如果您渴望使用延迟接口而不是 Promise 执行器接口,尽管有很多反对延迟接口的充分理由,您可以简单地编写一次代码,然后在任何地方使用它(我个人认为编码是一个坏主意这样,但你关于这个主题的大量问题表明你有不同的想法,所以就是这样):
function Deferred() {
var self = this;
var p = this.promise = new Promise(function(resolve, reject) {
self.resolve = resolve;
self.reject = reject;
});
this.then = p.then.bind(p);
this.catch = p.catch.bind(p);
if (p.finally) {
this.finally = p.finally.bind(p);
}
}
现在,您可以使用您似乎要求的界面:
var d = new Deferred();
d.resolve();
d.reject();
d.promise; // the actual promise
d.then(...) // can use .then() on either the Deferred or the Promise
d.promise.then(...)
这里是稍微更紧凑的 ES6 版本:
function Deferred() {
const p = this.promise = new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
this.then = p.then.bind(p);
this.catch = p.catch.bind(p);
if (p.finally) {
this.finally = p.finally.bind(p);
}
}
或者,您可以使用此
Deferred()
var request = new Deferred();
request.resolve();
request.then(handleSuccess, handleError);
但是,它具有本杰明指出的缺点,并且不被认为是编写 Promise 的最佳方式。