Promise.all:解析值的顺序
Promise.all: Order of resolved values
查看 MDN 似乎传递给 Promise.all 的 then()
回调的 values
包含按承诺顺序排列的值。例如:
var somePromises = [1, 2, 3, 4, 5].map(Promise.resolve);
return Promise.all(somePromises).then(function(results) {
console.log(results) // is [1, 2, 3, 4, 5] the guaranteed result?
});
谁能引用说明 values
应该按什么顺序排列的规范?
PS: 运行 这样的代码表明这似乎是真的,尽管这当然没有证据——这可能是巧合。
是的,results
中的值与 promises
中的值顺序相同。
人们可能会引用 ES6 spec on Promise.all
,尽管由于使用了迭代器 api 和通用的 promise 构造函数,它有点令人费解。但是,您会注意到每个解析器回调都有一个 [[index]]
属性,它是在 promise-array 迭代中创建的,用于设置结果数组的值。
根据您链接到的规范,Promise.all(iterable)
takes an iterable
as a parameter and internally calls PerformPromiseAll(iterator, constructor, resultCapability)
with it, where the latter loops over iterable
using IteratorStep(iterator)
。
解析是通过 Promise.all() Resolve
实现的,其中每个已解析的承诺都有一个内部 [[Index]]
插槽,它标记了原始输入中承诺的索引。
这意味着输出是严格排序的,因为您传递给 Promise.all() 的可迭代对象是严格排序的(例如,数组)。
您可以在下面看到这个动作 fiddle (ES6):
// Used to display results
const write = msg => {
document.body.appendChild(document.createElement('div')).innerHTML = msg;
};
// Different speed async operations
const slow = new Promise(resolve => {
setTimeout(resolve, 200, 'slow');
});
const instant = 'instant';
const quick = new Promise(resolve => {
setTimeout(resolve, 50, 'quick');
});
// The order is preserved regardless of what resolved first
Promise.all([slow, instant, quick]).then(responses => {
responses.map(response => write(response));
});
正如前面的答案已经指出的那样,Promise.all
将所有已解析的值与对应于原始 Promises 的输入顺序的数组聚合在一起(参见 Aggregating Promises)。
但是,我想指出的是,订单只保存在客户端!
对于开发人员来说,Promise 看起来是按顺序完成的,但实际上,Promise 的处理速度不同。当您使用远程后端时,了解这一点很重要,因为后端可能会以不同的顺序接收您的 Promise。
这是一个使用超时来演示问题的示例:
Promise.all
const myPromises = [
new Promise((resolve) => setTimeout(() => {resolve('A (slow)'); console.log('A (slow)')}, 1000)),
new Promise((resolve) => setTimeout(() => {resolve('B (slower)'); console.log('B (slower)')}, 2000)),
new Promise((resolve) => setTimeout(() => {resolve('C (fast)'); console.log('C (fast)')}, 10))
];
Promise.all(myPromises).then(console.log)
在上面显示的代码中,为 Promise.all
提供了三个 Promise(A、B、C)。三个 Promise 以不同的速度执行(C 最快,B 最慢)。这就是 Promise 的 console.log
语句按以下顺序显示的原因:
C (fast)
A (slow)
B (slower)
如果 Promise 是 AJAX 调用,则远程后端将按此顺序接收这些值。但在客户端 Promise.all
确保结果根据 myPromises
数组的原始位置排序。这就是为什么最终结果是:
['A (slow)', 'B (slower)', 'C (fast)']
如果你还想保证 Promise 的实际执行,那么你需要一个像 Promise 队列这样的概念。这是一个使用 p-queue 的示例(注意,您需要将所有 Promise 包装在函数中):
顺序承诺队列
const PQueue = require('p-queue');
const queue = new PQueue({concurrency: 1});
// Thunked Promises:
const myPromises = [
() => new Promise((resolve) => setTimeout(() => {
resolve('A (slow)');
console.log('A (slow)');
}, 1000)),
() => new Promise((resolve) => setTimeout(() => {
resolve('B (slower)');
console.log('B (slower)');
}, 2000)),
() => new Promise((resolve) => setTimeout(() => {
resolve('C (fast)');
console.log('C (fast)');
}, 10))
];
queue.addAll(myPromises).then(console.log);
结果
A (slow)
B (slower)
C (fast)
['A (slow)', 'B (slower)', 'C (fast)']
查看 MDN 似乎传递给 Promise.all 的 then()
回调的 values
包含按承诺顺序排列的值。例如:
var somePromises = [1, 2, 3, 4, 5].map(Promise.resolve);
return Promise.all(somePromises).then(function(results) {
console.log(results) // is [1, 2, 3, 4, 5] the guaranteed result?
});
谁能引用说明 values
应该按什么顺序排列的规范?
PS: 运行 这样的代码表明这似乎是真的,尽管这当然没有证据——这可能是巧合。
是的,results
中的值与 promises
中的值顺序相同。
人们可能会引用 ES6 spec on Promise.all
,尽管由于使用了迭代器 api 和通用的 promise 构造函数,它有点令人费解。但是,您会注意到每个解析器回调都有一个 [[index]]
属性,它是在 promise-array 迭代中创建的,用于设置结果数组的值。
根据您链接到的规范,Promise.all(iterable)
takes an iterable
as a parameter and internally calls PerformPromiseAll(iterator, constructor, resultCapability)
with it, where the latter loops over iterable
using IteratorStep(iterator)
。
解析是通过 Promise.all() Resolve
实现的,其中每个已解析的承诺都有一个内部 [[Index]]
插槽,它标记了原始输入中承诺的索引。
这意味着输出是严格排序的,因为您传递给 Promise.all() 的可迭代对象是严格排序的(例如,数组)。
您可以在下面看到这个动作 fiddle (ES6):
// Used to display results
const write = msg => {
document.body.appendChild(document.createElement('div')).innerHTML = msg;
};
// Different speed async operations
const slow = new Promise(resolve => {
setTimeout(resolve, 200, 'slow');
});
const instant = 'instant';
const quick = new Promise(resolve => {
setTimeout(resolve, 50, 'quick');
});
// The order is preserved regardless of what resolved first
Promise.all([slow, instant, quick]).then(responses => {
responses.map(response => write(response));
});
正如前面的答案已经指出的那样,Promise.all
将所有已解析的值与对应于原始 Promises 的输入顺序的数组聚合在一起(参见 Aggregating Promises)。
但是,我想指出的是,订单只保存在客户端!
对于开发人员来说,Promise 看起来是按顺序完成的,但实际上,Promise 的处理速度不同。当您使用远程后端时,了解这一点很重要,因为后端可能会以不同的顺序接收您的 Promise。
这是一个使用超时来演示问题的示例:
Promise.all
const myPromises = [
new Promise((resolve) => setTimeout(() => {resolve('A (slow)'); console.log('A (slow)')}, 1000)),
new Promise((resolve) => setTimeout(() => {resolve('B (slower)'); console.log('B (slower)')}, 2000)),
new Promise((resolve) => setTimeout(() => {resolve('C (fast)'); console.log('C (fast)')}, 10))
];
Promise.all(myPromises).then(console.log)
在上面显示的代码中,为 Promise.all
提供了三个 Promise(A、B、C)。三个 Promise 以不同的速度执行(C 最快,B 最慢)。这就是 Promise 的 console.log
语句按以下顺序显示的原因:
C (fast)
A (slow)
B (slower)
如果 Promise 是 AJAX 调用,则远程后端将按此顺序接收这些值。但在客户端 Promise.all
确保结果根据 myPromises
数组的原始位置排序。这就是为什么最终结果是:
['A (slow)', 'B (slower)', 'C (fast)']
如果你还想保证 Promise 的实际执行,那么你需要一个像 Promise 队列这样的概念。这是一个使用 p-queue 的示例(注意,您需要将所有 Promise 包装在函数中):
顺序承诺队列
const PQueue = require('p-queue');
const queue = new PQueue({concurrency: 1});
// Thunked Promises:
const myPromises = [
() => new Promise((resolve) => setTimeout(() => {
resolve('A (slow)');
console.log('A (slow)');
}, 1000)),
() => new Promise((resolve) => setTimeout(() => {
resolve('B (slower)');
console.log('B (slower)');
}, 2000)),
() => new Promise((resolve) => setTimeout(() => {
resolve('C (fast)');
console.log('C (fast)');
}, 10))
];
queue.addAll(myPromises).then(console.log);
结果
A (slow)
B (slower)
C (fast)
['A (slow)', 'B (slower)', 'C (fast)']