你如何同步解决一系列 es6 承诺?
How do you synchronously resolve a chain of es6 promises?
我有一个图书馆的功能,returns 一个承诺。我需要多次运行这个函数,但是每次迭代都必须等到上一个任务完成。
我的假设是我可以做到这一点:
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 的基本知识——但在阅读了几篇教程和博客文章后,我仍然迷失了方向。
您的 "non-loop" 解决方案也不应该有效。您必须将 函数 传递给 .then
,而不是承诺:
var p = Promise.resolve();
for (var i=1; i<=10; i++) {
(function(i) {
p = p.then(function() {
return promiseReturner(i);
});
}(i));
}
如果那个函数 returns 是一个承诺,那么你就会得到那种连锁效应。[=18=]
关于 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));
}
您可以使用 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
这是我用来解决相同问题的解决方案:
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');
})
如果您使用的是 es6,则可以使用 array.reduce
实现此目的。我想的还挺整齐的。
const functions = [/* array of functions which return promises */];
const finalPromise = functions.reduce(async (promise, asyncFn) => {
await promise;
return asyncFn();
}, Promise.resolve());
您可以通过 nsynjs 运行 您的代码,它将暂停执行 returns 承诺的每个函数,并等待承诺得到解决:
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>
彼此同步执行承诺可能很棘手。我在下面包含了一个使用 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);
});
我有一个图书馆的功能,returns 一个承诺。我需要多次运行这个函数,但是每次迭代都必须等到上一个任务完成。
我的假设是我可以做到这一点:
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 的基本知识——但在阅读了几篇教程和博客文章后,我仍然迷失了方向。
您的 "non-loop" 解决方案也不应该有效。您必须将 函数 传递给 .then
,而不是承诺:
var p = Promise.resolve();
for (var i=1; i<=10; i++) {
(function(i) {
p = p.then(function() {
return promiseReturner(i);
});
}(i));
}
如果那个函数 returns 是一个承诺,那么你就会得到那种连锁效应。[=18=]
关于 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));
}
您可以使用 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
这是我用来解决相同问题的解决方案:
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');
})
如果您使用的是 es6,则可以使用 array.reduce
实现此目的。我想的还挺整齐的。
const functions = [/* array of functions which return promises */];
const finalPromise = functions.reduce(async (promise, asyncFn) => {
await promise;
return asyncFn();
}, Promise.resolve());
您可以通过 nsynjs 运行 您的代码,它将暂停执行 returns 承诺的每个函数,并等待承诺得到解决:
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>
彼此同步执行承诺可能很棘手。我在下面包含了一个使用 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);
});