ES6 承诺执行顺序

ES6 promise execution order

我希望以下代码段的输出为 1, 2, 3, 4。但是,实际的输出顺序是1, 4, 3, 2.

self.promiseChain = new Promise(function (resolve, reject) {
  setTimeout(resolve, 4000);
}).then(function () {
  console.log(1);
});

self.promiseChain.then(function () {
  return new Promise(function (resolve, reject) {
    setTimeout(resolve, 3000);
  }).then(function () {
    console.log(2);
  });
});

self.promiseChain.then(function () {
  return new Promise(function (resolve, reject) {
    setTimeout(resolve, 2000);
  }).then(function () {
    console.log(3);
  });
});
self.promiseChain.then(function () {
  return new Promise(function (resolve, reject) {
    setTimeout(resolve, 200);
  }).then(function () {
    console.log(4);
  });
});

http://www.es6fiddle.net/imu5bhoj/

我读到的关于 promises 的所有内容都表明应该可以在这样的 'flat' 链中获得所需的顺序。显然我错过了一些细节?有人可以帮我指明正确的方向吗?

这里有一个 fiddle (http://www.es6fiddle.net/imu6vh1o/) 说明如何以非平面方式执行此操作,但它更难推理并使顺序链接变得笨拙。

我已经搜索过关于堆栈溢出的类似问题,但 none 他们使用一个简单的例子(我能找到)一般地回答了这个问题。

您刚刚将三个 .then() 处理程序附加到完全相同的 self.promiseChain 承诺。这是分支,而不是链接。对于承诺,这​​些是非常不同的行为。当 self.promiseChain 被解析时,这三个处理程序将一个接一个地被调用(无需等待结果)。因此,由此产生的三个异步操作将 运行 并行并在它们完成时完成,因此您会看到结果。

如果您希望对这四个操作进行排序,那么您实际上必须将它们一个接一个地链接起来,而不是全部链接到同一个承诺上。记住 .then() returns 一个新的承诺,它是您想要链接到的返回承诺以便对事物进行排序。

您正在这样做:

var p = somePromise();

p.then(fn1);
p.then(fn2);
p.then(fn3);

这将基本同时触发 fn1fn2fn3,并且 fn2 不会等待 fn1 promise 解决。

如果你想对操作进行排序,那么你需要这种类型的逻辑:

var p = somePromise();

p.then(fn1).then(fn2).then(fn3);

fn1 承诺完成之前不会执行 fn2 并且在 fn2 承诺完成之前不会执行 fn3 - 从而对异步操作进行排序。

如果它们真的被一个接一个地排序,情况会是这样。你实际上可以 运行 这个片段(但要有耐心,因为 运行 需要 10 秒):

var self = {};

self.promiseChain = new Promise(function (resolve, reject) {
  setTimeout(resolve, 4000);
}).then(function () {
  log(1);
});

var p = self.promiseChain.then(function () {
  return new Promise(function (resolve, reject) {
    setTimeout(resolve, 3000);
  }).then(function () {
    log(2);
  });
});

p = p.then(function () {
  return new Promise(function (resolve, reject) {
    setTimeout(resolve, 2000);
  }).then(function () {
    log(3);
  });
});
p = p.then(function () {
  return new Promise(function (resolve, reject) {
    setTimeout(resolve, 200);
  }).then(function () {
    log(4);
  });
});

p.then(function() {
   // last promise is done now
   log("all done");
});

function log(x) {
  var div = document.createElement("div");
  div.innerHTML = x;
  document.body.appendChild(div);
}

查看其他类似答案: