为什么Promise构造函数需要执行器?

问题描述 投票:0回答:2

使用 Promises 时,为什么不能在代码库的其他位置定义

resolve
reject
的触发器?

我不明白为什么

resolve
reject
逻辑应该本地化在声明承诺的地方。这是一个疏忽,还是强制使用
executor
参数有好处吗?


我认为执行器函数应该是可选的,并且它的存在应该决定承诺是否封装解析。如果没有这样的强制要求,承诺将具有更大的可扩展性,因为您不必立即启动异步。承诺也应该是可重置的。这是一个单次开关,1 或 0,

resolve()
reject()
。可以附加多种并行和顺序结果:
promise.then(parallel1)
promise.then(parallel2)
以及
promise.then(seq1).then(seq2)
,但有参考权限的玩家无法解析/拒绝进入切换

您可以稍后构建结果树,但您无法更改它们,也无法更改根(输入触发器)

老实说,顺序结果树也应该是可编辑的……假设在声明了许多承诺链之后,您想拼接一个步骤并做其他事情。重建承诺和每个顺序函数是没有意义的,特别是因为你甚至无法拒绝或销毁承诺......

javascript asynchronous promise
2个回答
17
投票

这被称为 Domenic 创造的揭示构造函数模式

基本上,这个想法是让您在该对象尚未完全构造时访问该对象的“部分”。引用多梅尼克的话:

我将其称为揭示构造函数模式,因为 Promise 构造函数揭示了其内部功能,但仅限于构造相关 Promise 的代码。解决或拒绝 Promise 的能力仅向构建代码透露,并且至关重要的是,不会向使用 Promise 的任何人透露。因此,如果我们将 p 交给另一个消费者,比如

过去

最初,Promise 与延迟对象一起工作,这在 JavaScript Promise 起源的 Twisted Promise 中是正确的。在旧的实现中,如 Angular 的

$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 执行器接口,尽管有很多反对延迟接口的充分理由,您可以简单地编写一次代码,然后在任何地方使用它(我个人认为编码是一个坏主意这样,但你关于这个主题的大量问题表明你有不同的想法,所以就是这样):

7
投票
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 的最佳方式。
    

© www.soinside.com 2019 - 2024. All rights reserved.