내가 이해하는 한, ES7 / ES2016에서 다중 await
코드를 코드에 넣는 .then()
것은 약속 과 체인을 연결 하는 것과 유사하게 작동하며 , 이는 팔러 렐이 아닌 차례로 실행됩니다. 예를 들어 다음 코드가 있습니다.
await someCall();
await anotherCall();
완료 anotherCall()
되었을 때만 호출 되는 것을 올바르게 이해 someCall()
합니까? 그것들을 병렬로 호출하는 가장 우아한 방법은 무엇입니까?
Node에서 사용하고 싶습니다. 비동기 라이브러리가있는 솔루션이 있습니까?
편집 : 나는이 질문에 제공된 솔루션에 만족하지 않습니다 : 비동기 생성기에서 약속을 병렬로 대기하지 않기 때문에 속도 저하 : 생성기 를 사용하고보다 일반적인 사용 사례에 대해 묻고 있습니다.
답변
당신은 기다릴 수 있습니다 Promise.all()
:
await Promise.all([someCall(), anotherCall()]);
결과를 저장하려면
let [someResult, anotherResult] = await Promise.all([someCall(), anotherCall()]);
참고 Promise.all
빠른 실패 수단이 곧 공급 약속 중 하나가 거부만큼, 다음 전체 물건 거부합니다.
const happy = (v, ms) => new Promise((resolve) => setTimeout(() => resolve(v), ms))
const sad = (v, ms) => new Promise((_, reject) => setTimeout(() => reject(v), ms))
Promise.all([happy('happy', 100), sad('sad', 50)])
.then(console.log).catch(console.log) // 'sad'
대신, 모든 약속이 이행 또는 거부 될 때까지 기다리려면을 사용할 수 있습니다 Promise.allSettled
. Internet Explorer는 기본적으로이 방법을 지원하지 않습니다.
const happy = (v, ms) => new Promise((resolve) => setTimeout(() => resolve(v), ms))
const sad = (v, ms) => new Promise((_, reject) => setTimeout(() => reject(v), ms))
Promise.allSettled([happy('happy', 100), sad('sad', 50)])
.then(console.log) // [{ "status":"fulfilled", "value":"happy" }, { "status":"rejected", "reason":"sad" }]
답변
TL; DR
Promise.all
병렬 함수 호출에 사용 하면 오류가 발생할 때 응답 동작이 올바르게 수행되지 않습니다.
먼저 모든 비동기 호출을 한 번에 실행하고 모든Promise
오브젝트를 확보하십시오 . 둘째, 물체에 사용 await
하십시오 Promise
. 이렇게하면 첫 번째 Promise
해결 을 기다리는 동안 다른 비동기 호출이 계속 진행됩니다. 전반적으로 가장 느린 비동기 호출이있는 한 대기합니다. 예를 들면 다음과 같습니다.
// Begin first call and store promise without waiting
const someResult = someCall();
// Begin second call and store promise without waiting
const anotherResult = anotherCall();
// Now we await for both results, whose async processes have already been started
const finalResult = [await someResult, await anotherResult];
// At this point all calls have been resolved
// Now when accessing someResult| anotherResult,
// you will have a value instead of a promise
JSbin 예 : http://jsbin.com/xerifanima/edit?js,console
주의 사항 : 모든 비동기 호출 후await
첫 번째 await
호출이 발생하는 한 호출이 동일한 회선 또는 다른 회선에 있는지 여부는 중요하지 않습니다 . JohnnyHK의 의견을 참조하십시오.
업데이트 : 이 답변은 @bergi의 답변 에 따라 오류 처리의 타이밍이 다르며 오류가 발생할 때 오류가 발생하지 않지만 모든 약속이 실행 된 후에 오류가 발생 하지 않습니다 . @jonny의 팁과 결과를 비교합니다. [result1, result2] = Promise.all([async1(), async2()])
, 다음 코드 스 니펫을 확인하십시오.
const correctAsync500ms = () => {
return new Promise(resolve => {
setTimeout(resolve, 500, 'correct500msResult');
});
};
const correctAsync100ms = () => {
return new Promise(resolve => {
setTimeout(resolve, 100, 'correct100msResult');
});
};
const rejectAsync100ms = () => {
return new Promise((resolve, reject) => {
setTimeout(reject, 100, 'reject100msError');
});
};
const asyncInArray = async (fun1, fun2) => {
const label = 'test async functions in array';
try {
console.time(label);
const p1 = fun1();
const p2 = fun2();
const result = [await p1, await p2];
console.timeEnd(label);
} catch (e) {
console.error('error is', e);
console.timeEnd(label);
}
};
const asyncInPromiseAll = async (fun1, fun2) => {
const label = 'test async functions with Promise.all';
try {
console.time(label);
let [value1, value2] = await Promise.all([fun1(), fun2()]);
console.timeEnd(label);
} catch (e) {
console.error('error is', e);
console.timeEnd(label);
}
};
(async () => {
console.group('async functions without error');
console.log('async functions without error: start')
await asyncInArray(correctAsync500ms, correctAsync100ms);
await asyncInPromiseAll(correctAsync500ms, correctAsync100ms);
console.groupEnd();
console.group('async functions with error');
console.log('async functions with error: start')
await asyncInArray(correctAsync500ms, rejectAsync100ms);
await asyncInPromiseAll(correctAsync500ms, rejectAsync100ms);
console.groupEnd();
})();
답변
최신 정보:
원래의 대답은 약속 거부를 올바르게 처리하는 것을 어렵게하고 때로는 불가능한 경우도 있습니다. 올바른 해결책은 다음을 사용하는 것입니다 Promise.all
.
const [someResult, anotherResult] = await Promise.all([someCall(), anotherCall()]);
원래 답변 :
둘 중 하나를 기다리기 전에 두 함수를 모두 호출하십시오.
// Call both functions
const somePromise = someCall();
const anotherPromise = anotherCall();
// Await both promises
const someResult = await somePromise;
const anotherResult = await anotherPromise;
답변
Promise.all ()없이 병렬로 수행하는 다른 방법이 있습니다.
먼저 숫자를 인쇄하는 두 가지 기능이 있습니다.
function printNumber1() {
return new Promise((resolve,reject) => {
setTimeout(() => {
console.log("Number1 is done");
resolve(10);
},1000);
});
}
function printNumber2() {
return new Promise((resolve,reject) => {
setTimeout(() => {
console.log("Number2 is done");
resolve(20);
},500);
});
}
이것은 순차적입니다.
async function oneByOne() {
const number1 = await printNumber1();
const number2 = await printNumber2();
}
//Output: Number1 is done, Number2 is done
이것은 병렬입니다 :
async function inParallel() {
const promise1 = printNumber1();
const promise2 = printNumber2();
const number1 = await promise1;
const number2 = await promise2;
}
//Output: Number2 is done, Number1 is done
답변
이는 Promise.allSettled () 로 수행 할 수 있으며 , 이는 Promise.all()
페일-패스트 동작 과 유사 하지만 실패하지 않습니다.
async function failure() {
throw "Failure!";
}
async function success() {
return "Success!";
}
const [failureResult, successResult] = await Promise.allSettled([failure(), success()]);
console.log(failureResult); // {status: "rejected", reason: "Failure!"}
console.log(successResult); // {status: "fulfilled", value: "Success!"}
참고 : 나는 그래서이 제한 브라우저를 지원하는 최첨단 기능입니다 강력하게 이 기능을위한 polyfill을 포함하는 것이 좋습니다.
답변
내가 만든 요지 결과, 해결 약속의 몇 가지 다른 방법을 테스트합니다. 작동하는 옵션을 보는 것이 도움이 될 수 있습니다.
답변
// A generic test function that can be configured
// with an arbitrary delay and to either resolve or reject
const test = (delay, resolveSuccessfully) => new Promise((resolve, reject) => setTimeout(() => {
console.log(`Done ${ delay }`);
resolveSuccessfully ? resolve(`Resolved ${ delay }`) : reject(`Reject ${ delay }`)
}, delay));
// Our async handler function
const handler = async () => {
// Promise 1 runs first, but resolves last
const p1 = test(10000, true);
// Promise 2 run second, and also resolves
const p2 = test(5000, true);
// Promise 3 runs last, but completes first (with a rejection)
// Note the catch to trap the error immediately
const p3 = test(1000, false).catch(e => console.log(e));
// Await all in parallel
const r = await Promise.all([p1, p2, p3]);
// Display the results
console.log(r);
};
// Run the handler
handler();
/*
Done 1000
Reject 1000
Done 5000
Done 10000
*/
p1, p2 및 p3을 설정하면 병렬로 엄격하게 실행되지는 않지만 실행을 유지하지 않으며 컨텍스트 오류를 catch로 잡을 수 있습니다.