[javascript] Node.js 고유의 Promise.all 처리가 병렬 또는 순차적입니까?
문서 가 명확하지 않기 때문에이 점을 분명히하고 싶습니다 .
Q1은 : 되어 Promise.all(iterable)
순차적으로 또는 병렬로 모두 약속 처리? 더 구체적으로 말하자면, 체인 약속을 실행하는 것과 같습니다.
p1.then(p2).then(p3).then(p4).then(p5)....
또는 모든 알고리즘의 몇 가지 다른 종류의 p1
, p2
, p3
, p4
, p5
, 등 (병렬) 같은 시간에 호출되는 결과가 모두 해결 (또는 거부) 즉시 반환됩니다?
Q2 : 경우 Promise.all
병렬 실행, 반복 가능 sequencially을 실행하는 편리한 방법은 무엇입니까?
참고 : Q 또는 Bluebird를 사용하고 싶지 않지만 모든 기본 ES6 사양을 사용하고 싶습니다.
답변
되어
Promise.all(iterable)
모든 약속을 실행?
아니요, 약속은 “실행”될 수 없습니다. 그들이 될 때 그들은 그들의 작업을 시작 만들어 그들은 단지 결과를 나타냅니다 – – 그리고 당신은 심지어에게 전달하기 전에 병렬로 모든 것을 실행하고 있습니다 Promise.all
.
Promise.all
단지 않습니다 await를 여러 약속을. 어떤 순서로 해결되는지 또는 계산이 병렬로 실행되는지는 중요하지 않습니다.
iterable을 순차적으로 실행하는 편리한 방법이 있습니까?
이미 약속이 있다면 많은 것을 할 수 없지만 Promise.all([p1, p2, p3, …])
(시퀀스 개념은 없습니다). 그러나 반복 가능한 비동기 함수가 있으면 실제로 순차적으로 실행할 수 있습니다. 기본적으로 당신은에서 얻을 필요가
[fn1, fn2, fn3, …]
에
fn1().then(fn2).then(fn3).then(…)
그리고 그 해결책은 다음을 사용하는 것입니다 Array::reduce
.
iterable.reduce((p, fn) => p.then(fn), Promise.resolve())
답변
병행하여
await Promise.all(items.map(async item => { await fetchItem(item) }))
장점 : 더 빠릅니다. 하나라도 실패하더라도 모든 반복이 실행됩니다.
순서대로
for (let i = 0; i < items.length; i++) {
await fetchItem(items[i])
}
장점 : 루프의 변수는 각 반복마다 공유 할 수 있습니다. 일반적인 명령형 동기 코드처럼 동작합니다.
답변
Bergis는 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 () 은 약속을 반환하는 함수를 기대합니다 . 따라서 괄호없이 함수 이름을 전달해야합니다! 이제 내 함수는 인수를 원하므로 인수를 사용하지 않는 익명 함수로 감싸 야합니다!
답변
@ Bergi의 대답을 자세히 설명하기 위해 (매우 간결하지만 이해하기 까다로운;)
이 코드는 배열의 각 항목을 실행하고 다음 ‘다음 체인’을 끝에 추가합니다.
function eachorder(prev,order) {
return prev.then(function() {
return get_order(order)
.then(check_order)
.then(update_order);
});
}
orderArray.reduce(eachorder,Promise.resolve());
이해가 되길 바랍니다.
답변
재귀 함수를 사용하여 비동기 함수를 사용하여 반복 가능한 iterable을 순차적으로 처리 할 수도 있습니다. 예를 들어 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"))
답변
async await를 사용 하면 일련의 약속을 쉽게 순차적으로 실행할 수 있습니다.
let a = [promise1, promise2, promise3];
async function func() {
for(let i=0; i<a.length; i++){
await a[i]();
}
}
func();
참고 : 위의 구현에서 약속이 거부되면 나머지는 실행되지 않습니다. 모든 약속을 실행하려면 await a[i]();
내부 를 감싸십시오.try catch
답변
평행
이 예를 참조하십시오
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();
코드를 실행하면 6 개의 약속 모두에 대해 “CALLED”콘솔이 표시되고 해결 될 때 시간 초과 후 6 개의 응답마다 동시에 콘솔 링됩니다.