ES6 Promise执行顺序

3
我希望以下代码片段的输出结果为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/

我读到的所有有关Promise的内容都表明在这样的'flat'链条中应该可以实现所需的顺序。 显然我错过了一些细节? 有人能帮忙指点一下吗?

这里有一个fiddle(http://www.es6fiddle.net/imu6vh1o/),介绍了如何以非平面方式解决此问题,但很难理解,并使连续链接变得笨拙。

我在stackoverflow上搜索了类似的问题,但没有找到使用简单明了的例子来通用回答这个问题。


1
你是不是指的是 self.promiseChain = self.promiseChain.then...? - elclanrs
是的 @elclanrs,看起来那就是我的问题! - l p
1个回答

10

你刚刚将三个.then()处理程序附加到完全相同的self.promiseChain承诺上。 这是分支而不是链接。 对于Promise来说,这些行为非常不同。 这些是三个处理程序,当self.promiseChain解决时,它们都将立即一个接一个地被调用(在等待结果的情况下)。 因此,所得到的三个异步操作将同时运行,并在完成时完成,因此您看到的结果。

如果你想要这四个操作按顺序执行,那么你必须实际上把它们链接在一起,而不是全部链接到同一个承诺上。 请记住,.then()返回一个新的承诺,在这个返回的承诺中链接事情。

你正在做以下事情:

var p = somePromise();

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

这将同时触发fn1fn2fn3fn2不会等待fn1的promise完成。

如果您想按顺序执行操作,则需要使用以下逻辑:

var p = somePromise();

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

在这段代码中,只有在fn1的promise完成后,才会执行fn2,而只有在fn2的promise完成后才会执行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);
}

查看其他类似答案:

按顺序执行本地js承诺

理解JavaScript承诺;堆栈和链接

promise.then.then与promise.then; promise.then之间有区别吗?


谢谢你,@jfriend00!我想我能理解为什么会被踩。看来我应该提高一下我的stackoverflow搜索技巧。无论如何,我的误解现在已经清晰明了,我终于可以抬起头来了! - l p

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接