【问题标题】:Chaining timeouts results in last timeout rejected?链接超时导致上次超时被拒绝?
【发布时间】:2015-02-12 19:47:18
【问题描述】:

我目前正在尝试将一些承诺与超时联系起来,无论达到哪个超时,它总是报告最后一个。我用 bluebird 和 Q 尝试过,结果相同,所以我认为我有一个普遍的问题。

代码基本上是这样的:

var Promise = require('bluebird');

Promise.delay(2000)
  .then(function() {
    return Promise.delay(2000);
  })
  .timeout(1000, 'Timeout 1')
  .then(function() {
    return Promise.delay(500);
  })
  .timeout(1000, 'Timeout 2')
  .then(function() {
    return Promise.delay(500);
  })
  .timeout(1000, 'Timeout 3');

我收到“未处理的拒绝超时错误:超时 3”。我想要的是获得超时 1。我尝试在每次超时后进行捕捉,但我得到的结果是一样的。

有没有办法让它工作而不完全拆分它?

【问题讨论】:

  • 当您在同一时间段内有多个超时时,据我所知,无法保证它们会运行的顺序。
  • @BenjaminGruenbaum 事实上,即使他们没有相同的时间段,也根本无法保证。所以以这种方式使用计时器根本不起作用:>

标签: javascript node.js promise q bluebird


【解决方案1】:

目前您有 3 次超时,都要求所有内容(您的整个链条)在 1 秒内完成。
我感觉您实际上希望为每个连续任务设置 3 次超时:

Promise.delay(2000)
.then(function() {
    return Promise.delay(2000)
    .timeout(1000, 'Timeout 1');
})
.then(function() {
    return Promise.delay(500)
    .timeout(1000, 'Timeout 2');
})
.then(function() {
    return Promise.delay(500)
    .timeout(1000, 'Timeout 3');
});

这将在 3 秒后以超时 1 被拒绝。

【讨论】:

  • 这正是我想做的。我昨天试过类似的,但它似乎混淆了。现在它正在工作。谢谢!
【解决方案2】:

Bluebird 不保证计时器的执行顺序。因此,如果您将三个超时设置为相同的时间跨度,我们不会强制执行哪个超时。如您所见,如果您在浏览器中运行此代码"Timeout 1" 将记录并且不会超时 3:

var p = Promise.delay(2000)
  .then(function() {
    return Promise.delay(2000);
  })
  .timeout(1000, 'Timeout 1')
  .then(function() {
    return Promise.delay(500);
  })
  .timeout(1000, 'Timeout 2')
  .then(function() {
    return Promise.delay(500);
  })
  .timeout(1000, 'Timeout 3');

p.reflect().then(function(res){
  document.body.innerHTML = JSON.stringify(res.reason().message);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/2.9.6/bluebird.js"></script>

从技术上讲,bluebird 遵守了合同。如果承诺尚未解决,则在指定的时间后假设没有异常,则它被拒绝。无论此处触发哪个计时器,这都是正确的。 这只是定时器的排序——你应该给它们不同的超时值。

当然,如果您在第一次超时后添加.catch(function(){})(最好是键入的,而不仅仅是一般的)在第一个.timeout 之后,您会得到不同的结果。

【讨论】:

    【解决方案3】:

    delaytimeout 使用环境的 setTimeout 函数,在 node.js 中绝对不能保证计时器将按什么顺序运行。您基本上需要假设setTimeout(..., 10) 可能在setTimeout(..., 10000) 之后运行,因此使您的代码依赖于较早的计时器在以后的计时器损坏后运行。

    【讨论】:

    • 实际上 - 在浏览器中指定,引用计时器规范的相关部分:Wait until any invocations of this algorithm started before this one whose timeout is equal to or less than this one's have completed. - 它是不做任何保证的节点:Node.js makes no guarantees about the exact timing of when the callback will fire, nor of the ordering things will fire in.
    • @BenjaminGruenbaum 这解释了为什么我总是在浏览器中得到 Timeout 1 ......但操作确实在使用 node.js
    猜你喜欢
    • 1970-01-01
    • 2012-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-03
    • 1970-01-01
    • 2021-01-08
    • 2015-02-23
    相关资源
    最近更新 更多