我想澄清这一点,因为文件不是很清楚;
Q1: Promise.all(iterable)是按顺序还是并行处理所有的promise ?或者,更具体地说,它相当于运行链式承诺
p1.then(p2).then(p3).then(p4).then(p5)....
或者它是某种其他类型的算法,其中所有的p1, p2, p3, p4, p5等同时(并行)被调用,并且结果在所有解决(或一个拒绝)后立即返回?
问题2:如果承诺。所有的运行都是并行的,是否有一种方便的方法来运行一个可迭代对象?
注意:我不想使用Q或蓝鸟,而是所有本地ES6规格。
也可以使用递归函数用异步函数顺序处理可迭代对象。例如,给定一个数组a,使用异步函数someAsyncFunction()处理:
var a = [1, 2, 3, 4, 5, 6]
function someAsyncFunction(n) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("someAsyncFunction: ", n)
resolve(n)
}, Math.random() * 1500)
})
}
//You can run each array sequentially with:
function sequential(arr, index = 0) {
if (index >= arr.length) return Promise.resolve()
return someAsyncFunction(arr[index])
.then(r => {
console.log("got value: ", r)
return sequential(arr, index + 1)
})
}
sequential(a).then(() => console.log("done"))
Bergi的回答让我使用Array.reduce走上了正确的轨道。
然而,为了让函数一个接一个地返回我的承诺,我必须添加更多的嵌套。
我真正的用例是一个文件数组,由于下游的限制,我需要按顺序一个接一个地传输…
这是我最后得出的结论:
getAllFiles().then( (files) => {
return files.reduce((p, theFile) => {
return p.then(() => {
return transferFile(theFile); //function returns a promise
});
}, Promise.resolve()).then(()=>{
console.log("All files transferred");
});
}).catch((error)=>{
console.log(error);
});
如前面的回答所示,使用:
getAllFiles().then( (files) => {
return files.reduce((p, theFile) => {
return p.then(transferFile(theFile));
}, Promise.resolve()).then(()=>{
console.log("All files transferred");
});
}).catch((error)=>{
console.log(error);
});
没有等到传输完成才开始另一个,而且“所有文件传输”的文本甚至在第一个文件传输开始之前就出现了。
不知道我做错了什么,但想分享对我有用的东西。
编辑:自从我写了这篇文章,我现在明白为什么第一个版本不起作用了。Then()期望函数返回一个promise。因此,您应该传入不带括号的函数名!现在,我的函数需要一个参数,所以我需要封装在一个匿名函数中,不带参数!
NodeJS不是并行运行承诺,而是并发运行,因为它是一个单线程事件循环架构。有可能通过创建一个新的子进程来利用多核CPU来并行运行。
并行Vs并发
其实,什么承诺。所做的就是,将Promise函数堆叠在适当的队列中(参见事件循环架构),并发运行它们(调用P1, P2,…),然后等待每个结果,然后解析Promise。所有的许诺都有结果。
的承诺。所有人都会在第一次承诺时失败,除非你必须自己处理拒绝。
并行和并发有一个很大的区别,第一个会在完全相同的时间在一个单独的进程中运行不同的计算,它们会按照自己的节奏进行,而另一个会一个接一个地执行不同的计算,而不需要等待前一个计算完成并同时进行,而不依赖彼此。
最后,回答你的问题,我保证。所有这些都不是并行或顺序执行,而是并发执行。
Promise.all(iterable)执行所有承诺吗?
不,承诺不能“执行”。它们在创建时就开始执行任务——它们只表示结果——甚至在将它们传递给Promise.all之前,您就可以并行执行所有的任务。
的承诺。一切都只等着多次承诺。它不关心它们解析的顺序,也不关心计算是否在并行运行。
是否有一种方便的方法来连续运行一个可迭代对象?
如果你已经许下承诺,除了承诺,你别无他法。All ([p1, p2, p3,…])(没有序列概念)。但是如果你确实有一个异步函数的可迭代对象,你确实可以按顺序运行它们。基本上你需要从
[fn1, fn2, fn3, …]
to
fn1().then(fn2).then(fn3).then(…)
解决方案是使用Array::reduce:
iterable.reduce((p, fn) => p.then(fn), Promise.resolve())
平行
请看这个例子
const resolveAfterTimeout = async i => {
return new Promise(resolve => {
console.log("CALLED");
setTimeout(() => {
resolve("RESOLVED", i);
}, 5000);
});
};
const call = async () => {
const res = await Promise.all([
resolveAfterTimeout(1),
resolveAfterTimeout(2),
resolveAfterTimeout(3),
resolveAfterTimeout(4),
resolveAfterTimeout(5),
resolveAfterTimeout(6)
]);
console.log({ res });
};
call();
通过运行代码,它将控制台“CALLED”为所有六个承诺,当他们被解决,它将控制台每6个响应超时后,在同一时间