ES6 promise execution order

不打扰是莪最后的温柔 提交于 2019-12-19 09:58:40

问题


I would expect the output for the following snippet to be 1, 2, 3, 4. But, the actual output order is 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/

Everything I've read about promises indicates it should be possible to get the desired order in a 'flat' chain like this. Apparently I'm missing some detail? Could someone help point me in the right direction?

Here's a fiddle (http://www.es6fiddle.net/imu6vh1o/) for how to do it in a non-flat way, but it's harder to reason about and makes sequential chaining awkward.

I've searched similar issues on stack overflow but none of them answer the question generically using a straightforward example (that I could find).


回答1:


You just attached three .then() handlers to the exact same self.promiseChain promise. This is branching, not chaining. With promises, those are very different behaviors. Those are three handlers that will all be called one immediately after the other (without waiting for results) when self.promiseChain is resolved. So, the resulting three async operations will run in parallel and finish whenever they finish, thus the results you see.

If you wanted these four operations to be sequenced, then you have to actually chain them one to another, not all chained onto the same promise. Remember .then() returns a new promise and it is that returned promise that you want to chain to in order to sequence things.

You are doing this:

var p = somePromise();

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

This will trigger fn1, fn2 and fn3 at basically the same time and fn2 will not wait for the fn1 promise to resolve.

If you want to sequence the operations, then you want this type of logic:

var p = somePromise();

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

This will not execute fn2 until the fn1 promise is done and will not execute fn3 until the fn2 promise is done - thus sequencing the async operations.

Here's how it would be if they were actually sequenced one after another. You can actually run this snippet (but have patience because it takes 10 seconds to run):

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);
}

See these other similar answers:

Execute native js promise in series

Understanding javascript promises; stacks and chaining

Is there a difference between promise.then.then vs promise.then; promise.then



来源:https://stackoverflow.com/questions/36526639/es6-promise-execution-order

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!