Saya ingin memperjelas hal ini, karena dokumentasinya tidak terlalu jelas tentang hal itu;
T1: Apakah Promise.all(iterable)
memproses semua janji secara berurutan atau paralel? Atau, lebih khusus, apakah itu setara dengan menjalankan janji dirantai seperti
p1.then(p2).then(p3).then(p4).then(p5)....
atau itu beberapa jenis lain dari algoritma di mana semua p1
, p2
, p3
, p4
, p5
, dll dipanggil pada waktu yang sama (secara paralel) dan hasilnya dikembalikan segera setelah semua tekad (atau satu menolak)?
T2: Jika Promise.all
berjalan secara paralel, apakah ada cara yang nyaman untuk menjalankan iterable secara berurutan?
Catatan : Saya tidak ingin menggunakan Q, atau Bluebird, tetapi semua spesifikasi ES6 asli.
javascript
node.js
promise
es6-promise
Yanick Rochon
sumber
sumber
Promise.all
mengeksekusi mereka secara paralel.node.js
danio.js
karena ini adalah tempat saya menggunakannya. Jadi, ya, implementasi V8 jika Anda mau.Promise.all
.new Promise(a).then(b); c();
a dieksekusi pertama, lalu c, lalu b. Bukan Janji. Semua yang menjalankan janji-janji ini, itu hanya menangani ketika mereka menyelesaikan.Jawaban:
Tidak, janji tidak bisa "dieksekusi". Mereka memulai tugas mereka ketika sedang dibuat - mereka hanya mewakili hasil - dan Anda mengeksekusi semuanya secara paralel bahkan sebelum meneruskannya
Promise.all
.Promise.all
tidak hanya menunggu beberapa janji. Tidak peduli urutan apa yang mereka selesaikan, atau apakah perhitungannya berjalan secara paralel.Jika Anda sudah memiliki janji, Anda tidak bisa berbuat banyak tetapi
Promise.all([p1, p2, p3, …])
(yang tidak memiliki urutan). Tetapi jika Anda memang memiliki iterable fungsi asinkron, Anda memang dapat menjalankannya secara berurutan. Pada dasarnya Anda harus mendapatkannyauntuk
dan solusi untuk melakukannya adalah menggunakan
Array::reduce
:sumber
then
urutan - nilai kembali adalah janji untukfn
hasil terakhir , dan Anda dapat membuat panggilan balik lainnya ke sana.fn1().then(p2).then(fn3).catch(…
? Tidak perlu menggunakan ekspresi fungsi.retValFromF1
dilewatkan kep2
, itulah yangp2
dilakukannya. Tentu, jika Anda ingin melakukan lebih banyak (melewati variabel tambahan, memanggil beberapa fungsi, dll) Anda perlu menggunakan ekspresi fungsi, meskipun mengubahp2
dalam array akan lebih mudahiterable
adalah[fn1, fn2, fn3, …]
arraySejajar
Keuntungan: Lebih cepat. Semua iterasi akan dieksekusi bahkan jika salah satu gagal.
Berurutan
Keuntungan: Variabel dalam loop dapat dibagi oleh setiap iterasi. Berperilaku seperti kode sinkron imperatif normal.
sumber
for (const item of items) await fetchItem(item);
await Promise.all(items.map(async item => { return await fetchItem(item).catch(e => e) }))
async
fungsinya adalah panggilan API dan Anda tidak ingin DDOS server. Anda memiliki kontrol yang lebih baik atas hasil individual dan kesalahan yang dilemparkan dalam eksekusi. Bahkan lebih baik Anda dapat memutuskan kesalahan apa untuk melanjutkan dan apa yang harus dilakukan.Jawaban Bergis membuat saya di jalur yang benar menggunakan Array.reduce.
Namun, untuk benar-benar mendapatkan fungsi mengembalikan janji saya untuk mengeksekusi satu demi satu, saya harus menambahkan beberapa lagi bersarang.
Kasing asli saya adalah array file yang harus saya transfer satu demi satu karena keterbatasan downstream ...
Inilah yang akhirnya saya dapatkan.
Seperti yang disarankan oleh jawaban sebelumnya, gunakan:
tidak menunggu untuk menyelesaikan transfer sebelum memulai yang lain dan juga teks "Semua file yang ditransfer" datang bahkan sebelum transfer file pertama dimulai.
Tidak yakin apa yang saya lakukan salah, tetapi ingin berbagi apa yang berhasil untuk saya.
Sunting: Sejak saya menulis posting ini, saya sekarang mengerti mengapa versi pertama tidak berfungsi. lalu () mengharapkan fungsi mengembalikan janji. Jadi, Anda harus memasukkan nama fungsi tanpa tanda kurung! Sekarang, fungsi saya ingin argumen jadi saya perlu membungkus dalam fungsi anonim tanpa mengambil argumen!
sumber
hanya untuk menguraikan jawaban @ Bergi (yang sangat ringkas, tetapi sulit dipahami;)
Kode ini akan menjalankan setiap item dalam array dan menambahkan 'rantai kemudian' berikutnya ke akhir;
harapan itu masuk akal.
sumber
Anda juga dapat memproses iterable secara berurutan dengan fungsi async menggunakan fungsi rekursif. Misalnya, diberikan array
a
untuk diproses dengan fungsi asinkronsomeAsyncFunction()
:sumber
array.prototype.reduce
jauh lebih baik dalam hal kinerja daripada fungsi rekursifreduce
mana Anda harus membangun seluruhthen()
rantai dalam satu langkah dan kemudian jalankan.NodeJS tidak menjalankan janji secara paralel, ia menjalankannya secara bersamaan karena ini adalah arsitektur loop peristiwa tunggal berulir. Ada kemungkinan untuk menjalankan berbagai hal secara paralel dengan menciptakan proses anak baru untuk memanfaatkan CPU multi-core.
Parallel Vs Concurent
Pada kenyataannya, apa yang
Promise.all
dilakukan adalah, menumpuk fungsi janji dalam antrian yang sesuai (lihat arsitektur loop acara) menjalankannya secara bersamaan (panggilan P1, P2, ...) kemudian menunggu setiap hasil, kemudian menyelesaikan Janji. Semua dengan semua janji hasil. Promise.all akan gagal pada janji pertama yang gagal, kecuali jika Anda sendiri yang mengelola penolakannya.Ada perbedaan besar antara paralel dan konkuren, yang pertama akan menjalankan perhitungan yang berbeda dalam proses yang terpisah pada waktu yang sama persis dan mereka akan berkembang di sana, sementara yang lain akan menjalankan perhitungan yang berbeda satu demi satu tanpa menunggu yang sebelumnya. perhitungan untuk menyelesaikan dan maju pada saat yang sama tanpa tergantung satu sama lain
Akhirnya, untuk menjawab pertanyaan Anda,
Promise.all
tidak akan mengeksekusi baik secara paralel atau berurutan tetapi bersamaan.sumber
Menggunakan async menunggu berbagai janji dapat dengan mudah dieksekusi secara berurutan:
Catatan: Dalam implementasi di atas, jika janji ditolak, sisanya tidak akan dieksekusi. Jika Anda ingin semua janji Anda dieksekusi, maka bungkus
await a[i]();
bagian dalam Andatry catch
sumber
paralel
lihat contoh ini
dengan menjalankan kode itu akan menghibur "DISEBUT" untuk semua enam janji dan ketika mereka diselesaikan itu akan menghibur setiap 6 tanggapan setelah batas waktu pada waktu yang sama
sumber
Jawaban Bergi membantu saya untuk membuat panggilan sinkron. Saya telah menambahkan contoh di bawah ini di mana kita memanggil setiap fungsi setelah fungsi sebelumnya dipanggil.
sumber
Anda dapat melakukannya dengan for loop.
fungsi async mengembalikan janji
jika Anda menulis kode berikut maka klien dibuat paralel
maka semua klien dibuat sejajar. tetapi jika Anda ingin membuat klien secara berurutan maka Anda harus menggunakan untuk loop
maka semua klien dibuat secara berurutan.
selamat coding :)
sumber
async
/await
hanya tersedia dengan transpiler, atau menggunakan mesin selain Node. Juga, Anda benar-benar tidak boleh bergaulasync
denganyield
. Di mana mereka bertindak sama dengan transpiler danco
, mereka benar-benar sangat berbeda dan seharusnya tidak saling menggantikan satu sama lain. Juga, Anda harus menyebutkan batasan ini karena jawaban Anda membingungkan bagi programmer pemula.Saya telah menggunakan untuk untuk menyelesaikan janji-janji berurutan. Saya tidak yakin apakah ini membantu di sini, tetapi inilah yang saya lakukan.
sumber
ini mungkin menjawab sebagian dari pertanyaan Anda.
ya, Anda dapat rantai array janji mengembalikan fungsi sebagai berikut ... (ini meneruskan hasil dari masing-masing fungsi ke yang berikutnya). Anda tentu saja dapat mengeditnya untuk memberikan argumen yang sama (atau tanpa argumen) ke setiap fungsi.
sumber
Saya sengaja menemukan halaman ini ketika mencoba untuk memecahkan masalah di NodeJS: reassembly potongan file. Pada dasarnya: Saya memiliki berbagai nama file. Saya perlu menambahkan semua file itu, dalam urutan yang benar, untuk membuat satu file besar. Saya harus melakukan ini secara tidak sinkron.
Modul 'fs' Node memang menyediakan appendFileSync tapi saya tidak ingin memblokir server selama operasi ini. Saya ingin menggunakan modul fs.promises dan menemukan cara untuk menyatukan semua ini. Contoh-contoh pada halaman ini tidak cukup berhasil bagi saya karena saya benar-benar membutuhkan dua operasi: fsPromises.read () untuk membaca file chunk, dan fsPromises.appendFile () untuk menyesuaikan dengan file tujuan. Mungkin jika saya lebih baik dengan javascript saya bisa membuat jawaban sebelumnya berfungsi untuk saya. ;-)
Saya sengaja menemukan ini ... https://css-tricks.com/why-using-reduce-to- berikutnyaally- resolve-promises- works/ ... dan saya dapat meretas bersama solusi yang berfungsi.
TLDR:
Dan inilah tes unit melati untuknya:
Saya harap ini membantu seseorang.
sumber