Порядок выполнения обещаний ES6

Я ожидаю, что вывод для следующего фрагмента будет 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/

Все, что я читал о обещаниях, указывает на то, что должна быть возможность получить желаемый порядок в такой «плоской» цепочке. Видимо я упускаю какую-то деталь? Может ли кто-нибудь помочь мне в правильном направлении?

Вот скрипт (http://www.es6fiddle.net/imu6vh1o/), как это сделать неплоским способом, но об этом труднее рассуждать, и это делает последовательное построение цепочки неудобным.

Я искал похожие проблемы с переполнением стека, но ни один из них не отвечает на вопрос в общем, используя простой пример (который я смог найти).


person l p    schedule 10.04.2016    source источник
comment
Вы имели в виду self.promiseChain = self.promiseChain.then...?   -  person elclanrs    schedule 10.04.2016
comment
Ага, @elclanrs, похоже, это была моя проблема!   -  person l p    schedule 10.04.2016


Ответы (1)


Вы только что прикрепили три обработчика .then() к одному и тому же обещанию self.promiseChain. Это ветвление, а не цепочка. С обещаниями это совсем другое поведение. Это три обработчика, которые будут вызываться один сразу после другого (не дожидаясь результатов) при разрешении self.promiseChain. Таким образом, результирующие три асинхронные операции будут выполняться параллельно и заканчиваться всякий раз, когда они завершатся, таким образом, результаты, которые вы видите.

Если вы хотите, чтобы эти четыре операции были упорядочены, вам нужно связать их одну с другой, а не связывать все с одним и тем же промисом. Помните, что .then() возвращает новое обещание, и именно это возвращенное обещание вы хотите связать, чтобы упорядочить вещи.

Вы делаете это:

var p = somePromise();

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

Это приведет к срабатыванию fn1, fn2 и fn3 практически одновременно, и fn2 не будет ждать разрешения обещания fn1.

Если вы хотите упорядочить операции, вам нужна логика такого типа:

var p = somePromise();

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

Это не будет выполнять fn2 до тех пор, пока не будет выполнено обещание fn1, и не будет выполнять fn3 до тех пор, пока не будет выполнено обещание fn2, таким образом упорядочивая асинхронные операции.

Вот как это было бы, если бы они были на самом деле секвенированы один за другим. Вы действительно можете запустить этот фрагмент (но наберитесь терпения, потому что он выполняется 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; обещаю.потом

person jfriend00    schedule 10.04.2016
comment
Спасибо, @jfriend00! Думаю, я могу понять отрицательные голоса. Думаю, мне следует освежить свои навыки поиска в стеке. В любом случае, теперь мое недопонимание кристально ясно, и я наконец могу оторвать голову от клавиатуры! - person l p; 10.04.2016