복사-붙여 넣기에 친숙하고 동시성 제한이있는 완전한 Promise.all()
/ map()
대체 기능에 대한 ES7 솔루션 입니다.
이와 유사하게 Promise.all()
반품 주문을 유지하고 비 약속 반품 값에 대한 폴백을 유지합니다.
또한 다른 솔루션 중 일부가 놓친 몇 가지 측면을 보여주기 때문에 다른 구현에 대한 비교도 포함했습니다.
용법
const asyncFn = delay => new Promise(resolve => setTimeout(() => resolve(), delay));
const args = [30, 20, 15, 10];
await asyncPool(args, arg => asyncFn(arg), 4);
이행
async function asyncBatch(args, fn, limit = 8) {
args = [...args];
const outs = [];
while (args.length) {
const batch = args.splice(0, limit);
const out = await Promise.all(batch.map(fn));
outs.push(...out);
}
return outs;
}
async function asyncPool(args, fn, limit = 8) {
return new Promise((resolve) => {
const argQueue = [...args].reverse();
let count = 0;
const outs = [];
const pollNext = () => {
if (argQueue.length === 0 && count === 0) {
resolve(outs);
} else {
while (count < limit && argQueue.length) {
const index = args.length - argQueue.length;
const arg = argQueue.pop();
count += 1;
const out = fn(arg);
const processOut = (out, index) => {
outs[index] = out;
count -= 1;
pollNext();
};
if (typeof out === 'object' && out.then) {
out.then(out => processOut(out, index));
} else {
processOut(out, index);
}
}
}
};
pollNext();
});
}
비교
const asyncFn = delay => new Promise(resolve => setTimeout(() => {
console.log(delay);
resolve(delay);
}, delay));
const args = [30, 20, 15, 10];
const out1 = await Promise.all(args.map(arg => asyncFn(arg)));
const out2 = await asyncPool(args, arg => asyncFn(arg), 2);
const out3 = await asyncBatch(args, arg => asyncFn(arg), 2);
console.log(out1, out2, out3);
결론
asyncPool()
이전 요청이 완료되는 즉시 새 요청을 시작할 수 있으므로 최상의 솔루션이어야합니다.
asyncBatch()
구현이 이해하기 쉽기 때문에 비교로 포함되지만 동일한 배치의 모든 요청이 다음 배치를 시작하려면 완료되어야하므로 성능이 더 느려집니다.
이 인위적인 예에서, 제한되지 않은 바닐라 Promise.all()
는 물론 가장 빠른 반면, 다른 것은 실제 혼잡 시나리오에서 더 바람직한 성능을 발휘할 수 있습니다.
최신 정보
다른 사람들이 이미 제안한 async-pool 라이브러리는 거의 동일하게 작동하고 Promise.race ()를 영리하게 사용하여보다 간결한 구현을 제공하므로 내 구현에 대한 더 나은 대안 일 수 있습니다. https://github.com/rxaviers/ async-pool / blob / master / lib / es7.js
내 대답이 여전히 교육적 가치를 제공 할 수 있기를 바랍니다.