Как вы синхронно разрешаете цепочку 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>