如何保证多个承诺的解决顺序?
How do I guarantee resolution order of multiple promises?
尝试学习一些现代 JS,尤其是 ECMAScript 6 Promises。我正在玩这个简单的测试:
let slow = new Promise((resolve) => {
setTimeout(function()
{
console.log('slow');
resolve();
}, 2000, 'slow');
});
let instant = new Promise((resolve) => {
console.log('instant');
resolve();
});
let quick = new Promise((resolve) => {
setTimeout(function()
{
console.log('quick');
resolve();
}, 1000, 'quick');
});
Promise.all([slow, instant, quick]).then(function(results) {
console.log('finished');
}, function(error) {
console.log(error);
});
我在这里想要的是同时启动所有的 Promises async。并在它们全部完成时记录下来。在控制台中,这按预期显示:"instant"、"quick"、"slow" 和 "finished"。
但是,如果我想确保 "instant" 在 "slow" 完成之前不会 echo/log 怎么办?也就是说,我希望控制台记录 "quick"、"slow"、"instant" 和 "finished"...但同时,它们仍必须同时启动异步。
我怎样才能做到这一点?
已更新
您不能同时启动它们并期望结果按照您当前代码要求的顺序登录。您可以执行以下操作:
let slow = new Promise((resolve) => {
setTimeout(() => resolve('slow'), 2000)
})
let instant = new Promise((resolve) => {
// In the future setImmediate can be used here to ensure async execution. For now, setTimeout with 0MS effectively does the same thing.
setTimeout(() => resolve('instant'), 0)
})
let quick = new Promise((resolve) => {
setTimeout(() => resolve('quick'), 1000)
})
Promise.all([slow, instant, quick]).then(function(results) {
for(let result of results) {
console.log(result)
}
console.log('finished')
}, function(err) {
console.error(err)
})
这会安排它们,然后在完成后以正确的顺序打印。
部分问题是日志记录发生在 setTimeout
方法中,而不是实际来自承诺解析。
const slow = new Promise((resolve) => {
setTimeout(() => {
console.log('slow - from setTimeout');
resolve('slow - from resolve');
}, 2000, 'slow');
});
const instant = new Promise((resolve) => {
console.log('instant - from setTimeout');
resolve('instant - from resolve');
});
const quick = new Promise((resolve) => {
setTimeout(() => {
console.log('quick - from setTimeout');
resolve('quick -from resolve');
}, 1000, 'quick');
});
Promise.all([slow, instant, quick]).then((results) => {
console.log(results);
console.log('finished');
}, (error) => {
console.log(error);
});
将值传递给 resolve
方法将 return Promise.all
中的所有内容。响应以数组的形式从每个承诺返回,您可以在所有响应完成后遍历这些响应。
Promise.all()
不是 return 预期结果所必需的。
您可以利用函数调用 return 的 Promise
构造函数,将应该传递给 console.log()
的值传递给 resolve()
或 reject()
。将值推送到数组。使用.then()
处理returned Promise
值,将returned值压入数组,return数组到下一个[=16处的回调函数参数=] 在链中。最后 .then()
in chain.
访问 Promise
值的链式数组
let results = [];
let pace = value => {console.log(value); results.push(value); return results};
let slow = () => new Promise((resolve) => {
setTimeout((value) => {
resolve(value);
}, 2000, "slow");
});
let instant = () => new Promise((resolve) => {
resolve("instant");
});
let quick = () => new Promise((resolve) => {
setTimeout((value) => {
resolve(value);
}, 1000, "quick");
});
slow().then(pace)
.then(instant).then(pace)
.then(quick).then(pace)
.then(res => console.log("finished, results:", res))
.catch(error => console.log(error));
首先,您的代码已经在 "same time" 开始了所有 3 个承诺。您还正确记录了 "finished"。据我从这个问题中了解到,您想 处理 按顺序排列的承诺结果,但让它们并行执行。
let slow = new Promise((resolve) => {
setTimeout(function()
{
resolve();
}, 2000);
});
let instant = new Promise((resolve) => {
resolve();
});
let quick = new Promise((resolve) => {
setTimeout(function()
{
resolve();
}, 1000);
});
instant.then(function(results) {
console.log("instant");
}).then(function(){return quick;}).then(function(results) {
console.log("quick");
}).then(function(){return slow;}).then(function(results) {
console.log("slow");
}).then(function(){ return Promise.all([slow, instant, quick]);}).then(function(results) {
console.log('finished');
}).catch(function(error) {
console.log(error);
});
这将保证您按顺序处理决议。
注意:在你的例子中,你使用setTimeout
,它保证按时间顺序调用处理程序,所以你现有的代码将已经记录"instant"、"quick"、"slow"、"finished"。我提供的代码保证了 任何 组具有不同解析时间的承诺的顺序。
明确地说,你想在这里做的是立即启动所有承诺,并在每个承诺的结果进入时按特定顺序显示,对吗?
在那种情况下,我可能会这样做:
let slow = new Promise((resolve) => {
setTimeout(function()
{
// Rather than log here, we resolve to the value we want to log
resolve('slow');
}, 2000, 'slow');
});
let instant = new Promise((resolve) => {
resolve('instant');
});
let quick = new Promise((resolve) => {
setTimeout(function()
{
resolve('quick');
}, 1000, 'quick');
});
// All Promises are now running. Let's print the results...
// First wait for the result of `slow`...
slow.then((result) => {
// Result received...
console.log(result);
// Now wait for the result of instant...
instant.then((result) => {
// Result received...
console.log(result);
// Now wait for the result of quick...
quick.then((result) => {
// Result received...
console.log(result);
}).then((result) => {
// Done
console.log('finished');
});
});
});
请注意,与 cchamberlain's 不同,此方法 不会 在开始返回结果之前等待所有承诺解决。它 returns 返回结果,但不违反保持结果有序的要求。 (要验证这一点,请尝试将 quick
的等待时间更改为 2500 毫秒,并观察其结果在 instant
后 500 毫秒打印。)根据您的应用程序,这可能是可取的。
上面的代码有点乱,但幸好有了 ES2017 中新的 async/await
语法,它可以变得更清晰:
let slow = new Promise((resolve) => {
setTimeout(function()
{
// Rather than log here, we resolve to the value we want to log
resolve('slow');
}, 2000, 'slow');
});
let instant = new Promise((resolve) => {
resolve('instant');
});
let quick = new Promise((resolve) => {
setTimeout(function()
{
resolve('quick');
}, 1000, 'quick');
});
// All Promises are now running. Let's print the results...
async function logResults(...promises) {
for (let promise of promises) {
console.log(await promise);
}
}
logResults(slow, instant, quick).then(() => console.log('finished'));
Try in Babel。注意:以上代码目前无法在没有 Babel 的现代浏览器中运行(截至 2016 年 10 月)。在未来的浏览器中它会。
如果问题的要求是
"instant" doesn't echo/log before "slow"
和
but at the same time, they must still all start at the same time
async.
您只需要重新排序传递给 Promise.all()
的可迭代对象中的元素,或者在对每个元素调用 console.log()
之前调整链接到 Promise.all()
的 .then()
中的结果数组结果数组。
如果要求是
"How to wait for another promise?"
或
"How do I guarantee resolution order of multiple promises?"
参见 。
Promise.all
passes an array of values from all the promises in the
iterable object that it was passed. The array of values maintains the
order of the original iterable object, not the order that the promises
were resolved in. If something passed in the iterable array is not a
promise, it's converted to one by Promise.resolve
.
let slow = new Promise((resolve) => {
setTimeout(function(value) {
resolve(value);
}, 2000, "slow");
});
let instant = new Promise((resolve) => {
resolve("instant");
});
let quick = new Promise((resolve) => {
setTimeout(function(value) {
resolve(value);
}, 1000, "quick");
});
Promise.all([slow, instant, quick]).then(function(results) {
console.log("finished");
console.log(results.join("\n"))
}, function(error) {
console.log(error);
});
尝试学习一些现代 JS,尤其是 ECMAScript 6 Promises。我正在玩这个简单的测试:
let slow = new Promise((resolve) => {
setTimeout(function()
{
console.log('slow');
resolve();
}, 2000, 'slow');
});
let instant = new Promise((resolve) => {
console.log('instant');
resolve();
});
let quick = new Promise((resolve) => {
setTimeout(function()
{
console.log('quick');
resolve();
}, 1000, 'quick');
});
Promise.all([slow, instant, quick]).then(function(results) {
console.log('finished');
}, function(error) {
console.log(error);
});
我在这里想要的是同时启动所有的 Promises async。并在它们全部完成时记录下来。在控制台中,这按预期显示:"instant"、"quick"、"slow" 和 "finished"。
但是,如果我想确保 "instant" 在 "slow" 完成之前不会 echo/log 怎么办?也就是说,我希望控制台记录 "quick"、"slow"、"instant" 和 "finished"...但同时,它们仍必须同时启动异步。
我怎样才能做到这一点?
已更新
您不能同时启动它们并期望结果按照您当前代码要求的顺序登录。您可以执行以下操作:
let slow = new Promise((resolve) => {
setTimeout(() => resolve('slow'), 2000)
})
let instant = new Promise((resolve) => {
// In the future setImmediate can be used here to ensure async execution. For now, setTimeout with 0MS effectively does the same thing.
setTimeout(() => resolve('instant'), 0)
})
let quick = new Promise((resolve) => {
setTimeout(() => resolve('quick'), 1000)
})
Promise.all([slow, instant, quick]).then(function(results) {
for(let result of results) {
console.log(result)
}
console.log('finished')
}, function(err) {
console.error(err)
})
这会安排它们,然后在完成后以正确的顺序打印。
部分问题是日志记录发生在 setTimeout
方法中,而不是实际来自承诺解析。
const slow = new Promise((resolve) => {
setTimeout(() => {
console.log('slow - from setTimeout');
resolve('slow - from resolve');
}, 2000, 'slow');
});
const instant = new Promise((resolve) => {
console.log('instant - from setTimeout');
resolve('instant - from resolve');
});
const quick = new Promise((resolve) => {
setTimeout(() => {
console.log('quick - from setTimeout');
resolve('quick -from resolve');
}, 1000, 'quick');
});
Promise.all([slow, instant, quick]).then((results) => {
console.log(results);
console.log('finished');
}, (error) => {
console.log(error);
});
将值传递给 resolve
方法将 return Promise.all
中的所有内容。响应以数组的形式从每个承诺返回,您可以在所有响应完成后遍历这些响应。
Promise.all()
不是 return 预期结果所必需的。
您可以利用函数调用 return 的 Promise
构造函数,将应该传递给 console.log()
的值传递给 resolve()
或 reject()
。将值推送到数组。使用.then()
处理returned Promise
值,将returned值压入数组,return数组到下一个[=16处的回调函数参数=] 在链中。最后 .then()
in chain.
Promise
值的链式数组
let results = [];
let pace = value => {console.log(value); results.push(value); return results};
let slow = () => new Promise((resolve) => {
setTimeout((value) => {
resolve(value);
}, 2000, "slow");
});
let instant = () => new Promise((resolve) => {
resolve("instant");
});
let quick = () => new Promise((resolve) => {
setTimeout((value) => {
resolve(value);
}, 1000, "quick");
});
slow().then(pace)
.then(instant).then(pace)
.then(quick).then(pace)
.then(res => console.log("finished, results:", res))
.catch(error => console.log(error));
首先,您的代码已经在 "same time" 开始了所有 3 个承诺。您还正确记录了 "finished"。据我从这个问题中了解到,您想 处理 按顺序排列的承诺结果,但让它们并行执行。
let slow = new Promise((resolve) => {
setTimeout(function()
{
resolve();
}, 2000);
});
let instant = new Promise((resolve) => {
resolve();
});
let quick = new Promise((resolve) => {
setTimeout(function()
{
resolve();
}, 1000);
});
instant.then(function(results) {
console.log("instant");
}).then(function(){return quick;}).then(function(results) {
console.log("quick");
}).then(function(){return slow;}).then(function(results) {
console.log("slow");
}).then(function(){ return Promise.all([slow, instant, quick]);}).then(function(results) {
console.log('finished');
}).catch(function(error) {
console.log(error);
});
这将保证您按顺序处理决议。
注意:在你的例子中,你使用setTimeout
,它保证按时间顺序调用处理程序,所以你现有的代码将已经记录"instant"、"quick"、"slow"、"finished"。我提供的代码保证了 任何 组具有不同解析时间的承诺的顺序。
明确地说,你想在这里做的是立即启动所有承诺,并在每个承诺的结果进入时按特定顺序显示,对吗?
在那种情况下,我可能会这样做:
let slow = new Promise((resolve) => {
setTimeout(function()
{
// Rather than log here, we resolve to the value we want to log
resolve('slow');
}, 2000, 'slow');
});
let instant = new Promise((resolve) => {
resolve('instant');
});
let quick = new Promise((resolve) => {
setTimeout(function()
{
resolve('quick');
}, 1000, 'quick');
});
// All Promises are now running. Let's print the results...
// First wait for the result of `slow`...
slow.then((result) => {
// Result received...
console.log(result);
// Now wait for the result of instant...
instant.then((result) => {
// Result received...
console.log(result);
// Now wait for the result of quick...
quick.then((result) => {
// Result received...
console.log(result);
}).then((result) => {
// Done
console.log('finished');
});
});
});
请注意,与 cchamberlain's quick
的等待时间更改为 2500 毫秒,并观察其结果在 instant
后 500 毫秒打印。)根据您的应用程序,这可能是可取的。
上面的代码有点乱,但幸好有了 ES2017 中新的 async/await
语法,它可以变得更清晰:
let slow = new Promise((resolve) => {
setTimeout(function()
{
// Rather than log here, we resolve to the value we want to log
resolve('slow');
}, 2000, 'slow');
});
let instant = new Promise((resolve) => {
resolve('instant');
});
let quick = new Promise((resolve) => {
setTimeout(function()
{
resolve('quick');
}, 1000, 'quick');
});
// All Promises are now running. Let's print the results...
async function logResults(...promises) {
for (let promise of promises) {
console.log(await promise);
}
}
logResults(slow, instant, quick).then(() => console.log('finished'));
Try in Babel。注意:以上代码目前无法在没有 Babel 的现代浏览器中运行(截至 2016 年 10 月)。在未来的浏览器中它会。
如果问题的要求是
"instant" doesn't echo/log before "slow"
和
but at the same time, they must still all start at the same time async.
您只需要重新排序传递给 Promise.all()
的可迭代对象中的元素,或者在对每个元素调用 console.log()
之前调整链接到 Promise.all()
的 .then()
中的结果数组结果数组。
如果要求是
"How to wait for another promise?"
或
"How do I guarantee resolution order of multiple promises?"
参见
Promise.all
passes an array of values from all the promises in the iterable object that it was passed. The array of values maintains the order of the original iterable object, not the order that the promises were resolved in. If something passed in the iterable array is not a promise, it's converted to one byPromise.resolve
.
let slow = new Promise((resolve) => {
setTimeout(function(value) {
resolve(value);
}, 2000, "slow");
});
let instant = new Promise((resolve) => {
resolve("instant");
});
let quick = new Promise((resolve) => {
setTimeout(function(value) {
resolve(value);
}, 1000, "quick");
});
Promise.all([slow, instant, quick]).then(function(results) {
console.log("finished");
console.log(results.join("\n"))
}, function(error) {
console.log(error);
});