Как вы синхронно разрешаете цепочку es6 promises?

У меня есть функция из библиотеки, которая возвращает обещание. Мне нужно запустить эту функцию несколько раз, но каждая итерация должна дождаться выполнения предыдущей задачи.

Мое предположение заключалось в том, что я мог бы это сделать:

promiseReturner(1)
  .then(promiseReturner(2)
  .then(promiseReturner(3)
  .then(...)

Что можно упростить с помощью цикла:

var p = Promise.resolve();
for (var i=1; i<=10; i++) {
  p = p.then(promiseReturner(i));
}

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

Здесь код, который я написал, чтобы продемонстрировать свою попытку.

Ответы

Ответ 1

Ваше "нециклическое" решение также не должно работать. Вы должны передать функцию на .then, а не на обещание:

var p = Promise.resolve();
for (var i=1; i<=10; i++) {
  (function(i) {
      p = p.then(function() {
          return promiseReturner(i);
      });
  }(i));
}

Если эта функция возвращает обещание, вы получаете эффект цепочки.

Подробнее о promises на MDN.


Может быть упрощено с помощью let (и функций стрелок):

var p = Promise.resolve();
for (let i=1; i<=10; i++) {
    p = p.then(() => promiseReturner(i));
}

Или .bind (это ES5):

var p = Promise.resolve();
for (var i=1; i<=10; i++) {
    p = p.then(promiseReturner.bind(null, i));
}

Ответ 2

Если вы используете es6, вы можете достичь этого, используя array.reduce. Я думаю довольно аккуратно.

const functions = [/* array of functions which return promises */];
const finalPromise = functions.reduce(async (promise, asyncFn) => {
  await promise;
  return asyncFn();
}, Promise.resolve());

Ответ 3

Вы можете использовать async/await с помощью генераторов es6 и библиотеки типа co.

co(function* () {
  while(upto < 10) {
    var result = yield Promise.resolve(true);
  }
  return result;
}).then(function (value) {
  console.log(value);
}, function (err) {
  console.error(err.stack);
});

Вот некоторые подробности, как это работает: http://davidwalsh.name/async-generators

Ответ 4

Здесь решение, которое я использовал для решения одной и той же проблемы:

var recursiveFunction = function(values) {
  return new Promise(function(resolve, reject) {
    if (values.length <= 0) {
        return resolve();
    } else {
        return promiseReturner(values[0]).then(function() {
            values.shift();
            return recursiveFunction(values).then(function() {
              resolve();
            });
        });
      }
  });
}

recursiveFunction([1,2]).then(function(r) {
 console.warn('Finished solving promises sequentially');
})

Ответ 5

Выполнение обещаний синхронно по отношению друг к другу может быть сложным. Ниже приведен пример, в котором используются обещания Axios, но вы можете заменить их на свои. Удачи!

const get = (endpoint = '/', params = {}) => {
  // return axios promise
  return axios({
    method: 'get',
    url: apiHost + endpoint,
    headers: { 'Authorization': 'Token ' + this.state.token },
    params: params,
  });
};

get('/api/some-endpoint/')
  .then((response) => {
    console.log(response);
    //return next promise
    return get('/api/another-endpoint/');
  }).then((response) => {
    console.log(response);
    // return next promise
    return get('/api/yet-endpoint');
  }).then((response) => {
    console.log(response);
    // return next promise
    return get('/api/last-endpoint/');
  }).then((response) => {
    console.log(response);
    // finished, no more promises left in the chain
  })
  .catch(function (error) {
    console.log('Error getting data', error);
  });

Ответ 6

Вы можете запустить свой код через nsynjs, он приостанавливает выполнение каждой функции, которая возвращает обещание, и будет ждать, пока обещание Решили:

var promiseReturner = function(i) {
    return new Promise(function(resolve, reject) {
        setTimeout(function(){
            resolve("result is "+i)
        }, 1000);
    });
};

function synchronousCode() {
    for (var i=1; i<=10; i++) {
        var p=promiseReturner(i); // nsynjs will pause here until promise is resolved
        console.log(p.data); // `data` will contain result of the promise
    }
};
	
nsynjs.run(synchronousCode, null, function(){
	console.log("finish");
});
<script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>