Javascript ES6 会承诺支持'done' api吗?

Posted

技术标签:

【中文标题】Javascript ES6 会承诺支持\'done\' api吗?【英文标题】:Will Javascript ES6 promise support 'done' api?Javascript ES6 会承诺支持'done' api吗? 【发布时间】:2014-12-27 08:32:38 【问题描述】:

例如

p = new Promise(function (resolve, reject) 
    throw 'err';
);

p.done();

在大多数 Promise polyfill 库中,done 会抛出错误,并且当前执行将退出。

但是如果我们使用p.then(),什么都不会发生。错误被诺言吞没了。如果我们使用p.catch,我们将无法退出当前执行。我想达到以下目标:

try 
    // something
 catch (err) 
    if (check(err)) 
        throw err;
    

【问题讨论】:

html5rocks.com/en/tutorials/es6/promises 中的任何有用信息 这就是为什么推荐使用像 bluebird 这样的 Promise 库的原因。 Bluebird 可以很好地处理未捕获的异常,给你一堆导致当前事件的承诺。请参阅 Bluebird Promise 对象上的 longStackTraces 方法。 @SecondRikudo 原生 Promise 最终也很可能都这样做 - 例如,他们已经在 Firefox 中这样做了。 请注意,这个问题自 ES2015 起已过时 【参考方案1】:

不,AFAIK done 不是规范的一部分。为了模仿它的行为,你应该在下一个滴答声中抛出异常,在 Promise 链的范围之外:

p.catch(function(e)  
    setTimeout(function()  throw e; );
);

这基本上是库实现done 的方式。参见 Q 文档的摘录:

很像then,但是...所产生的拒绝原因作为异常抛出在事件循环的未来轮次中

自己实现done

如果您想按照通常理解的方式实现done 的近似语义,则类似于:

Promise.prototype.done = function(onFulfilled, onRejected) 
    this
        .then(onFulfilled, onRejected)
        .catch(function(e) 
            setTimeout(function()  throw e; );
        )
    ;
;

设置错误处理程序

如果您想自己处理这些错误,您可以设置一个错误处理程序:

Promise.onError = function(e) 
    console.log("The sky is falling", e);
    throw e;
;

然后在下一个滴答声中调用处理程序:

Promise.prototype.done = function(onFulfilled, onRejected) 
    this
        .then(onFulfilled, onRejected)
        .catch(function(e) 
            setTimeout(Promise.onError || function()  throw e; , 1, e);
        )
    ;
;

【讨论】:

【参考方案2】:

TC39 的当前声明是,这个问题可以并且应该在浏览器引擎中使用开发者工具本地解决。这就是他们反对在原生 API 中提供 done 的原因。

这确实是一个有争议的决定,有关该问题的讨论,请参阅以下链接:

https://github.com/domenic/promises-unwrapping/issues/19

http://mozilla.6506.n7.nabble.com/Where-d-Promise-done-go-td281461.html

https://github.com/promises-aplus/promises-spec/issues/43

https://github.com/slightlyoff/Promises/issues/33

【讨论】:

虽然我非常不同意您的观点,但我非常重视您在这些讨论中的奉献和参与。另外-感谢您在此处发布它们,它们非常相关。关于上下文的好答案。【参考方案3】:

没有。

.done 不仅可能在未来版本的规范中不受支持 - 它是不需要的。引用 Mariusz 链接到的线程:

家庭:

它仍然容易出错:如果你犯了错误,甚至一次都不遵守规则,你可能会永远沉默错误。

Mark Miller(率先提出承诺的概念):

请注意,weak-refs,希望在 ES7 中,将为我们提供我们需要的一种诊断工具来弥补这一差距。使用weak-refs,如果在没有通知任何处理程序的情况下收集了被拒绝的promise,我们可以安排它生成诊断。 Promise 实现必须将原因保留在 Promise 的执行程序(事后 gc 处理程序)中,以便在发现 Promise 已被拒绝后进行诊断报告。

Yehuda Kats 关于 RSVP 的错误处理程序:

我们在 RSVP 中采用的方法是安装一个默认抛出的未处理的 Promise 监视器。

如果您知道您将附加异步错误处理程序,则可以通过附加 noop 故障处理程序来选择特定的 Promise 退出此行为。我们可能会为此加糖(.undone :p)

根据我们的经验,将负担从每个人转移到可能想要附加异步错误处理程序的人是合适的。

而且,从规范之前的实际回购中,Domenic 说:

将通过将未处理的拒绝跟踪功能集成到开发工具中来完成工作。据我了解,大多数 TC39 人员以及我自己都认为这足以完成规范。


规范委员会不只是忽略.done,他们认为这是不必要的并且容易出错。新的现代 Promise 库会自动检测未处理的拒绝 - 其中两个示例是开创这一想法的 When Promise 和 Bluebird Promise。

.done 是一个人工制品 - 源于浏览器无法检测到未处理的拒绝。事实是 - 确定性地检测它们是不可能的,但对于绝大多数情况来说,这是完全可能的。

不相信我?打开 Firefox 并使用它的原生 Promise:

p = new Promise(function (resolve, reject) 
    throw 'err';
);
// Logs as error: Unhandled error: `err`

简单地说 - firefox 使用垃圾收集钩子来确定 Promise 是否处于未处理状态,并触发默认在屏幕上写入的全局错误处理程序。

现在,问题是本机 Promise 还不是很实用 - 因为在 IE 中它们不存在,并且在 Chrome 中未处理的拒绝检测尚未实现 - 但它即将到来并且它会在那里。同时,您可以使用像 Bluebird 这样的 ES6 兼容库,它会为您进行拒绝跟踪。

如果你想完成 polyfill(我强烈推荐反对)- torazaburo 的 polyfill 有一些缺点。它在 Promise 原型上声明了一个可枚举的属性,通常这不是规范的设计方式——您应该subclass Promise 以扩展它们而不是猴子修补它们——遗憾的是,目前没有实现支持这一点.

简而言之:

等待原生 promise 稳定后再使用它们 - 同时您可以使用像 Bluebird 这样实现规范的库。当它稳定下来时,没有.done 将根本不是问题。 利用模式检测错误 - 例如在此处查看the disposer pattern。 在可用时使用开发人员工具,长堆栈跟踪和异步调试是一大优势。另请注意,如果您想要有意义的堆栈跟踪,则不应抛出字符串。

祝你好运,编码愉快。

【讨论】:

以上是关于Javascript ES6 会承诺支持'done' api吗?的主要内容,如果未能解决你的问题,请参考以下文章

类函数中的 Javascript ES6 承诺

ES6新特性之 promise

JavaScript ES6承诺循环[重复]

javascript ES6

带有 ES6 / Bluebird 承诺的对象方法

扩展 Javascript 承诺并在构造函数中解决或拒绝它