【问题标题】:Why does JS Promise .then() evaluate before resolve()为什么 JS Promise .then() 在 resolve() 之前求值
【发布时间】:2017-02-06 20:17:23
【问题描述】:

我一直在使用 Promises,并且我将以下代码组合在一起,这些代码的行为并不像我期望的那样。您可以在此处的 Fiddle 中运行它:

https://fiddle.sencha.com/#view/editor&fiddle/1pmk

function log(txt) {
  var lapsed = new Date().getTime() - START;
  console.log(lapsed, txt);
}
START = new Date().getTime();

var promise = new Promise(function promiseExecutor(resolve, reject) {
  log('in Promise 1 Executor');
  setTimeout(function onSetTimeout() {
    log('in Promise 1 Timeout');
    resolve(123);
  }, 500);
});

var promise2 = new Promise(function promise2Executor(resolve, reject) {
  log('in Promise 2 Executor');
  setTimeout(function onSetTimeout() {
    log('in Promise 2 Timeout');
    resolve(123);
  }, 1000);
});

// sequence
promise
  .then(promise2)
  .then(function onPromiseDone(p) {
    // TODO: why this executes before promise2 resolve?
    log('ALL Promise Done! ' + p);
  });

如果您查看控制台,您会注意到“ALL Promise Done”消息在第一个承诺被解决后立即触发,然后半秒后第二个承诺被解决......

最终的 then(onPromiseDone) 怎么可能在没有 resolve() 的情况下被触发?

现在,我了解到 Promise 执行器功能立即开始运行,这不是“排序”的好例子。我可以通过将我的承诺包装在“延迟”函数中来实现正确的行为,如下所示:

https://fiddle.sencha.com/#view/editor&fiddle/1pml

不过,这并不能回答我对原始小提琴的问题,我将重复一遍:

最终的 then(onPromiseDone) 怎么可能在没有 resolve() 的情况下被触发?

谢谢!

【问题讨论】:

  • 请注意,promise1 和 promise2 都是背靠背启动的,没有涉及到任何顺序。您还不如使用 Promise.all
  • 你好像在找Promise.all([promise, promise2]).then(onPromiseDone)
  • 1) 我在帖子中讨论了“背靠背”场景;这如何原谅最终 onPromiseDone() 在没有 resolve() 的情况下触发?
  • @IvanJouikov 你没有给 .then 一个回调来打电话......所以它只是继续。由于 promise1 已解决,第二个调用它的回调。
  • @IvanJouikov,如果then 的参数不是函数,那就像noop 一样好。

标签: javascript promise


【解决方案1】:

.then 接收两个参数:一个在 Promise 成功解析时触发的函数和一个在 Promise 被拒绝时调用的函数(可以省略)。

在您的示例中,您将一个新的承诺作为参数传递。

为了实现你的目标(链),我建议这样:

var promise = new Promise(function (resolve, reject) {
  log('in Promise 1 Executor');
  setTimeout(function onSetTimeout() {
    log('in Promise 1 Timeout');
    resolve(123);
  }, 2000);
});


var callback = function(val) {
  log('received from the first promisse: ' + val)
  return new Promise(function (resolve, reject) {
    log('in Promise 2 Executor');
    setTimeout(function onSetTimeout() {
      log('in Promise 2 Timeout');
      resolve(456);
    }, 2000);
  });
}


// Promise.all([promise, promise2]) // parallelize
// sequence
promise
  .then(callback)
  .then(function(val) {
        log('received from the second promisse: ' + val)
        log('ALL Promise Done! ');
    }
  );

这样,您运行promisse 并将callback 函数设置为.then 参数。所以,当第一个 setTimeout 完成时,它会调用 resolve 并调用 callback 函数,这将创建一个新的 Promise,然后设置新的 setTimeout

将输出:

0 "in Promise 1 Executor"
2002 "in Promise 1 Timeout"
2002 "received from the first promisse: 123"
2002 "in Promise 2 Executor"
4002 "in Promise 2 Timeout"
4003 "received from the second promisse: 456"
4003 "ALL Promise Done! "

工作小提琴:https://jsfiddle.net/mrlew/L8b8fow9/

在@Bergi 发表评论后编辑。谢谢。

【讨论】:

  • 啊,是的,我忘记了“then”函数需要返回一个承诺......基本上在我原来的例子中,我可以将“.then(promise2)”行替换为“.then(function (){return promise2;})" ...如此微妙的变化,但有很大的不同。承诺不容易!感谢您的帮助!
  • 在我的原始示例中,我可以将“.then(promise2)”行替换为“.then(function(){return promise2;})” 就是这样。不客气!
  • 这是个坏主意,因为promise2 中的超时仍然不会在promise 解决时立即开始。如果您想按顺序运行它们,请将 promise2 的创建放在该回调中;如果您想并行运行它们,请使用Promise.all 等待它们。
  • @Bergi 你是对的!我编辑了答案。感谢您的贡献。
  • @IvanJouikov 请检查答案的编辑版本,现在它的行为符合预期。
猜你喜欢
  • 1970-01-01
  • 2019-01-20
  • 2019-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-13
  • 2020-12-27
  • 1970-01-01
相关资源
最近更新 更多