Javascript Node.js 原生 Promise.all 是并行处理还是顺序处理?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30823653/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is Node.js native Promise.all processing in parallel or sequentially?
提问by Yanick Rochon
I would like to clarify this point, as the documentationis not too clear about it;
我想澄清这一点,因为文档对此不太清楚;
Q1:Is Promise.all(iterable)processing all promises sequentially or in parallel? Or, more specifically, is it the equivalent of running chained promises like
Q1:是Promise.all(iterable)按顺序还是并行处理所有的promise?或者,更具体地说,它是否相当于运行链式承诺,如
p1.then(p2).then(p3).then(p4).then(p5)....
or is it some other kind of algorithm where all p1, p2, p3, p4, p5, etc. are being called at the same time (in parallel) and results are returned as soon as all resolve (or one rejects)?
或者是一些其他类型的算法的所有p1,p2,p3,p4,p5,等是被称为在同一时间(并行)和结果尽快返回所有的决心(或一个不合格品)?
Q2:If Promise.allruns in parallel, is there a convenient way to run an iterable sequencially?
Q2:如果Promise.all并行运行,有没有方便的方式来顺序运行一个可迭代对象?
Note: I don't want to use Q, or Bluebird, but all native ES6 specs.
注意:我不想使用 Q 或 Bluebird,而是所有原生 ES6 规范。
回答by Bergi
Is
Promise.all(iterable)executing all promises?
是否正在
Promise.all(iterable)执行所有承诺?
No, promises cannot "be executed". They start their task when they are being created- they represent the results only - and youare executing everything in parallel even before passing them to Promise.all.
不,承诺不能“被执行”。它们在被创建时就开始了它们的任务——它们只代表结果——并且你甚至在将它们传递给Promise.all.
Promise.alldoes only awaitmultiple promises. It doesn't care in what order they resolve, or whether the computations are running in parallel.
Promise.all只等待多个承诺。它不关心它们以什么顺序解析,或者计算是否并行运行。
is there a convenient way to run an iterable sequencially?
有没有一种方便的方法来按顺序运行可迭代对象?
If you already have your promises, you can't do much but Promise.all([p1, p2, p3, …])(which does not have a notion of sequence). But if you do have an iterable of asynchronous functions, you can indeed run them sequentially. Basically you need to get from
如果你已经有你的承诺,你不能做太多但Promise.all([p1, p2, p3, …])(它没有顺序的概念)。但是,如果您确实有一个可迭代的异步函数,您确实可以按顺序运行它们。基本上你需要从
[fn1, fn2, fn3, …]
to
到
fn1().then(fn2).then(fn3).then(…)
and the solution to do that is using Array::reduce:
解决方案是使用Array::reduce:
iterable.reduce((p, fn) => p.then(fn), Promise.resolve())
回答by david_adler
In parallel
在平行下
await Promise.all(items.map(async item => { await fetchItem(item) }))
Advantages: Faster. All iterations will be executed even if one fails.
优点:更快。即使一次失败,所有的迭代都会被执行。
In sequence
按顺序
for (let i = 0; i < items.length; i++) {
await fetchItem(items[i])
}
Advantages: Variables in the loop can be shared by each iteration. Behaves like normal imperative synchronous code.
优点:循环中的变量可以被每次迭代共享。表现得像普通的命令式同步代码。
回答by tkarls
Bergis answer got me on the right track using Array.reduce.
Bergis 的回答使我使用 Array.reduce 走上了正确的轨道。
However, to actually get the functions returning my promises to execute one after another I had to add some more nesting.
然而,为了真正让函数返回我的承诺以一个接一个地执行,我不得不添加更多的嵌套。
My real use case is an array of files that I need to transfer in order one after another due to limits downstream...
我真正的用例是一组文件,由于下游限制,我需要一个接一个地传输这些文件...
Here is what I ended up with.
这就是我的结果。
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);
});
As previous answers suggest, using:
正如以前的答案所暗示的那样,使用:
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);
});
didn't wait for the transfer to complete before starting another and also the "All files transferred" text came before even the first file transfer was started.
在开始另一个之前没有等待传输完成,并且“所有文件传输”文本甚至在第一个文件传输开始之前就出现了。
Not sure what I did wrong, but wanted to share what worked for me.
不确定我做错了什么,但想分享对我有用的东西。
Edit: Since I wrote this post I now understand why the first version didn't work. then() expects a functionreturning a promise. So, you should pass in the function name without parentheses! Now, my function wants an argument so then I need to wrap in in a anonymous function taking no argument!
编辑:自从我写了这篇文章,我现在明白为什么第一个版本不起作用了。then() 需要一个返回承诺的函数。所以,你应该传入不带括号的函数名!现在,我的函数需要一个参数,所以我需要包含在一个不带参数的匿名函数中!
回答by TimoSolo
just to elaborate on @Bergi's answer (which is very succinct, but tricky to understand ;)
只是为了详细说明@Bergi的答案(非常简洁,但很难理解;)
This code will run each item in the array and add the next 'then chain' to the end;
这段代码将运行数组中的每一项,并将下一个“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());
hope that makes sense.
希望这是有道理的。
回答by Mark Meyer
You can also process an iterable sequentially with an async function using a recursive function. For example, given an array ato process with asynchronous function someAsyncFunction():
您还可以使用递归函数通过异步函数按顺序处理可迭代对象。例如,给定一个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"))
回答by Ayan
Using async awaitan array of promises can easily be executed sequentially:
使用async await可以轻松地按顺序执行一组 promise:
let a = [promise1, promise2, promise3];
async function func() {
for(let i=0; i<a.length; i++){
await a[i]();
}
}
func();
Note: In above implementation, if a promise is rejected, the rest wouldn't be executed.If you want all your promises to be executed, then wrap your await a[i]();inside try catch
注:在上面的实现,如果承诺被拒绝,其余的将不会是executed.If要执行所有的承诺,那么你的包裹await a[i]();里面try catch
回答by Adrien De Peretti
NodeJS does not run promises in parallel, it runs them concurrently since it's a single threaded event loop architecture. There is a possibility to run things in parallel by creating a new child process to take advantage of the multiple core CPU.
NodeJS 不会并行运行 promise,而是并发运行它们,因为它是单线程事件循环架构。通过创建一个新的子进程来利用多核 CPU,可以并行运行事物。
In fact, what Promise.alldoes is, stacking the promises function in the appropriate queue (see event loop architecture) running them concurrently (call P1, P2,...) then waiting for each result, then resolving the Promise.all with all the promises results.
Promise.all will fail at the first promise which fail, unless you have manage the rejection yourself.
事实上,什么Promise.all是将 promises 函数堆叠在适当的队列中(参见事件循环架构)并发运行它们(调用 P1、P2、...)然后等待每个结果,然后用所有的 promise 解析 Promise.all结果。Promise.all 将在第一个失败的承诺中失败,除非你自己管理了拒绝。
There is a major difference between parallel and concurrent, the first one will run different computation in separate process at exactly the same time and they will progress at there rythme, while the other one will execute the different computation one after another without waiting for the previous computation to finish and progress at the same time without depending on each other.
并行和并发有一个很大的区别,第一个会在不同的进程中同时运行不同的计算,它们会按照那里的节奏进行,而另一个会一个接一个地执行不同的计算,而不需要等待前一个计算同时完成和进行而不相互依赖。
Finally, to answer your question, Promise.allwill not execute neither in parallel or sequentially but concurrently.
最后,回答你的问题,Promise.all不会并行或顺序执行,而是并发执行。
回答by Chintan Rajpara
parallel
平行线
see this example
看这个例子
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();
by running the code it'll console "CALLED" for all six promises and when they are resolved it will console every 6 responses after timeout at the same time
通过运行代码,它将为所有六个承诺控制台“调用”,当它们被解决时,它将在超时后同时控制台每 6 个响应
回答by Nithi
Bergi's answer helped me to make the call synchronous.I have added an example below where we call each function after the previous function is called.
Bergi 的回答帮助我使调用同步。我在下面添加了一个示例,我们在调用前一个函数之后调用每个函数。
function func1 (param1) {
console.log("function1 : " + param1);
}
function func2 () {
console.log("function2");
}
function func3 (param2, param3) {
console.log("function3 : " + param2 + ", " + param3);
}
function func4 (param4) {
console.log("function4 : " + param4);
}
param4 = "Kate";
//adding 3 functions to array
a=[
()=>func1("Hi"),
()=>func2(),
()=>func3("Lindsay",param4)
];
//adding 4th function
a.push(()=>func4("dad"));
//below does func1().then(func2).then(func3).then(func4)
a.reduce((p, fn) => p.then(fn), Promise.resolve());
回答by Jay
I stumbled across this page while trying to solve a problem in NodeJS: reassembly of file chunks. Basically: I have an array of filenames. I need to append all those files, in the correct order, to create one large file. I must do this asynchronously.
我在尝试解决 NodeJS 中的一个问题时偶然发现了这个页面:文件块的重组。基本上:我有一个文件名数组。我需要以正确的顺序附加所有这些文件,以创建一个大文件。我必须异步执行此操作。
Node's 'fs' module does provide appendFileSync but I didn't want to block the server during this operation. I wanted to use the fs.promises module and find a way to chain this stuff together. The examples on this page didn't quite work for me because I actually needed two operations: fsPromises.read() to read in the file chunk, and fsPromises.appendFile() to concat to the destination file. Maybe if I was better with javascript I could have made the previous answers work for me. ;-)
Node 的“fs”模块确实提供了 appendFileSync,但我不想在此操作期间阻止服务器。我想使用 fs.promises 模块并找到一种方法将这些东西链接在一起。此页面上的示例对我来说不太适用,因为我实际上需要两个操作: fsPromises.read() 读取文件块,以及 fsPromises.appendFile() 连接到目标文件。也许如果我使用 javascript 更好,我可以让以前的答案对我有用。;-)
I stumbled across this... https://css-tricks.com/why-using-reduce-to-sequentially-resolve-promises-works/...and I was able to hack together a working solution.
我偶然发现了这个...... https://css-tricks.com/why-using-reduce-to-sequentially-resolve-promises-works/......我能够一起破解一个有效的解决方案。
TLDR:
域名注册地址:
/**
* sequentially append a list of files into a specified destination file
*/
exports.append_files = function (destinationFile, arrayOfFilenames) {
return arrayOfFilenames.reduce((previousPromise, currentFile) => {
return previousPromise.then(() => {
return fsPromises.readFile(currentFile).then(fileContents => {
return fsPromises.appendFile(destinationFile, fileContents);
});
});
}, Promise.resolve());
};
And here's a jasmine unit test for it:
这是一个茉莉花单元测试:
const fsPromises = require('fs').promises;
const fsUtils = require( ... );
const TEMPDIR = 'temp';
describe("test append_files", function() {
it('append_files should work', async function(done) {
try {
// setup: create some files
await fsPromises.mkdir(TEMPDIR);
await fsPromises.writeFile(path.join(TEMPDIR, '1'), 'one');
await fsPromises.writeFile(path.join(TEMPDIR, '2'), 'two');
await fsPromises.writeFile(path.join(TEMPDIR, '3'), 'three');
await fsPromises.writeFile(path.join(TEMPDIR, '4'), 'four');
await fsPromises.writeFile(path.join(TEMPDIR, '5'), 'five');
const filenameArray = [];
for (var i=1; i < 6; i++) {
filenameArray.push(path.join(TEMPDIR, i.toString()));
}
const DESTFILE = path.join(TEMPDIR, 'final');
await fsUtils.append_files(DESTFILE, filenameArray);
// confirm "final" file exists
const fsStat = await fsPromises.stat(DESTFILE);
expect(fsStat.isFile()).toBeTruthy();
// confirm content of the "final" file
const expectedContent = new Buffer('onetwothreefourfive', 'utf8');
var fileContents = await fsPromises.readFile(DESTFILE);
expect(fileContents).toEqual(expectedContent);
done();
}
catch (err) {
fail(err);
}
finally {
}
});
});
I hope it helps someone.
我希望它可以帮助某人。

