Yan*_*hon 151 javascript node.js promise es6-promise
我想澄清这一点,因为文件不太清楚;
Q1:是Promise.all(iterable)处理所有的承诺顺序或并行?或者,更具体地说,它是否相当于运行链式承诺
p1.then(p2).then(p3).then(p4).then(p5)....
Run Code Online (Sandbox Code Playgroud)
或者是一些其他类型的算法的所有p1,p2,p3,p4,p5,等是被称为在同一时间(并行)和结果尽快返回所有的决心(或一个拒绝)?
Q2:如果Promise.all并行运行,是否有一种方便的方式来运行可迭代的顺序?
注意:我不想使用Q或Bluebird,而是使用所有原生ES6规范.
Ber*_*rgi 223
正在
Promise.all(iterable)执行所有承诺吗?
不,承诺不能"被执行".他们在创建任务时开始他们的任务- 他们只代表结果 - 你甚至在传递它们之前并行执行所有事情Promise.all.
Promise.all只等待多个承诺.它不关心它们解决的顺序,或者计算是否并行运行.
是否有一种方便的方法来运行可迭代的顺序?
如果你已经有了你的承诺,你就做不了多少Promise.all([p1, p2, p3, …])(但没有一个序列的概念).但是如果你有一个可迭代的异步函数,你确实可以按顺序运行它们.基本上你需要得到
[fn1, fn2, fn3, …]
Run Code Online (Sandbox Code Playgroud)
至
fn1().then(fn2).then(fn3).then(…)
Run Code Online (Sandbox Code Playgroud)
并且解决方案是使用Array::reduce:
iterable.reduce((p, fn) => p.then(fn), Promise.resolve())
Run Code Online (Sandbox Code Playgroud)
dav*_*ler 49
await Promise.all(items.map(async item => { await fetchItem(item) }))
Run Code Online (Sandbox Code Playgroud)
优点:更快.即使一个失败,也会执行所有迭代.
for (let i = 0; i < items.length; i++) {
await fetchItem(items[i])
}
Run Code Online (Sandbox Code Playgroud)
优点:循环中的变量可以由每次迭代共享.表现得像普通的命令式同步代码.
Adr*_*tti 18
NodeJS 不会并行运行 promise,而是并发运行它们,因为它是单线程事件循环架构。通过创建一个新的子进程来利用多核 CPU,可以并行运行事物。
事实上,什么Promise.all是将 promises 函数堆叠在适当的队列中(参见事件循环架构)并发运行它们(调用 P1、P2、...)然后等待每个结果,然后用所有的 promise 解析 Promise.all结果。Promise.all 将在第一个失败的承诺中失败,除非你自己管理了拒绝。
并行和并发有一个很大的区别,第一个会在不同的进程中同时运行不同的计算,它们会按照那里的节奏进行,而另一个会一个接一个地执行不同的计算,而不需要等待前一个计算同时完成和进行而不相互依赖。
最后,回答你的问题,Promise.all不会并行或顺序执行,而是并发执行。
tka*_*rls 10
贝尔吉斯的回答使用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);
});
Run Code Online (Sandbox Code Playgroud)
如先前的答案所示,使用:
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);
});
Run Code Online (Sandbox Code Playgroud)
在启动另一个文件之前没有等待传输完成,并且在启动第一个文件传输之前也发送了"所有文件传输"文本.
不知道我做错了什么,但想分享对我有用的东西.
编辑:自从我写这篇文章后,我现在明白为什么第一个版本不起作用.then()期望一个函数返回一个promise.所以,你应该传递没有括号的函数名称!现在,我的函数需要一个参数,所以我需要在一个不带参数的匿名函数中包装!
您还可以使用递归函数通过异步函数按顺序处理可迭代对象。例如,给定一个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"))Run Code Online (Sandbox Code Playgroud)
只是为了详细说明@Bergi的答案(非常简洁,但很难理解;)
此代码将运行数组中的每个项目并将下一个“then chain”添加到末尾:
function eachorder(prev,order) {
return prev.then(function() {
return get_order(order)
.then(check_order)
.then(update_order);
});
}
orderArray.reduce(eachorder,Promise.resolve());
Run Code Online (Sandbox Code Playgroud)