【问题标题】:Nested promise handlers嵌套的承诺处理程序
【发布时间】:2014-03-26 10:38:07
【问题描述】:

牢记以下声明:

一旦对象进入已解决或已拒绝状态,它就会保持该状态。回调仍然可以添加到已解决或已拒绝的 Deferred 中——它们将立即执行。

来自http://api.jquery.com/jQuery.Deferred/

您希望这段代码产生什么效果:

var d = $.Deferred();

var a = function() {
    d.done(function() {
        console.log('inner');
    });
    
    console.log('outer');
};

d.done(a);

d.resolve();

?

我希望它是 inner,然后是 outer。而我检查的任何 jquery 版本都不是这种情况。

你会认为这是一个错误还是我错过了描述中的要点?

对应的JSFiddle:http://jsfiddle.net/U8AGc/

UPD:问题的一些背景知识:我希望 a 方法的行为相似,无论它是如何被调用的:就像 a()d.done(a)

【问题讨论】:

  • 这只是不遵循 Promises/A+ 时的怪事之一 :-)

标签: javascript jquery promise


【解决方案1】:

我希望 a 方法的行为相似,无论它是如何被调用的:就像 a() 或 d.done(a)

没有。 d.done(a) 并不总是立即调用 a() - 最突出的是当 d 尚未解决时。

Promises/A+ 通过要求始终异步触发处理程序来解决这种歧义,即在这里您可以期望 outer 在任何情况下都在 inner 之前。

我希望它是inner,然后是outer

jQuery.Callbacks 阻止了这种情况,它有一个显式的firing flag,用于在处理程序中不立即执行处理程序;而是将添加的处理程序附加到队列中。它也是一个防止堆栈溢出的功能,它通过“锁定”它来简化 fire 函数。

您会认为这是一个错误还是我错过了描述中的要点?

我会考虑不遵循 Promises/A+ 的错误 :-) 描述只是没有处理这个 - 非常不常见 - 特殊情况。

我想说的是,解决延迟问题上的处理程序即使在解决后仍会自动执行,“立即”并不一定意味着“从.done 内同步”,而是而是“马上,尽快”。

【讨论】:

  • "d.done(a) 并不总是立即调用 a()" --- 这就是引用的文档所述。 “回调仍然可以添加到已解决或已拒绝的 Deferred 中——它们将立即执行。”
  • 是的,但它没有说明当您向 当前正在解决或拒绝的 Deferred 添加回调时会发生什么 :-)
  • “已解决或被拒绝” --- 还不够。 jsfiddle.net/U8AGc/2 它可能应该以某种方式提到嵌套它们的事实。是嵌套导致了这种情况,而不是执行顺序。
  • 呃,你完全正确。对于 Promises/A+ 的明确性,我没能找到好的链接,但我希望github.com/promises-aplus/promises-spec/issues/68 能给你一个开始。
  • @zerkms 立即非排队执行承诺会导致竞争条件和不确定的代码路径(先执行什么?)这是一个可怕的想法。存在异步蹦床要求有很好的理由。就像 Bergi 说的那样 - 这是 jQuery 完全丢球。
【解决方案2】:

这是发生了什么:

var a = function() {
    // the function logging 'inner' is *added* to the call stack
    d.done(function() {
        console.log('inner');
    });
    // 'outer' is logged
    console.log('outer');
};
// `a` has finished executing, then the anonymous function logs 'inner'

我在your JSFiddle 中添加了一个带有堆栈跟踪* 的日志 - 你可以看到函数 a 在记录 inner 的匿名函数中找不到 - jQuery 调用它一次 @987654327 @ 已完成执行。

jQuery 源代码中的相关行是found here(注意它正在添加到队列中)。

*来自here的跟踪代码

【讨论】:

    猜你喜欢
    • 2019-02-24
    • 2020-03-29
    • 2018-12-03
    • 1970-01-01
    • 2019-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多