Berikut adalah solusi ES7 saya untuk copy-paste ramah dan fitur lengkap Promise.all()
/ map()
alternatif, dengan batas konkurensi.
Mirip dengan Promise.all()
itu mempertahankan urutan pengembalian serta fallback untuk nilai-nilai pengembalian yang tidak menjanjikan.
Saya juga menyertakan perbandingan implementasi yang berbeda karena ini menggambarkan beberapa aspek yang terlewatkan oleh beberapa solusi lain.
Pemakaian
const asyncFn = delay => new Promise(resolve => setTimeout(() => resolve(), delay));
const args = [30, 20, 15, 10];
await asyncPool(args, arg => asyncFn(arg), 4);
Penerapan
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();
});
}
Perbandingan
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);
Kesimpulan
asyncPool()
harus menjadi solusi terbaik karena memungkinkan permintaan baru untuk dimulai segera setelah permintaan sebelumnya selesai.
asyncBatch()
disertakan sebagai perbandingan karena implementasinya lebih mudah dipahami, tetapi performanya harus lebih lambat karena semua permintaan dalam batch yang sama harus diselesaikan untuk memulai batch berikutnya.
Dalam contoh yang dibuat-buat ini, vanilla non-limited Promise.all()
tentu saja yang tercepat, sementara yang lain bisa tampil lebih diinginkan dalam skenario kemacetan dunia nyata.
Memperbarui
Pustaka async-pool yang telah disarankan orang lain mungkin merupakan alternatif yang lebih baik untuk implementasi saya karena bekerja hampir sama dan memiliki implementasi yang lebih ringkas dengan penggunaan Promise.race () yang cerdas: https://github.com/rxaviers/ async-pool / blob / master / lib / es7.js
Semoga jawaban saya tetap bisa menjadi nilai pendidikan.