Saya punya pertanyaan tentang Array.forEach
implementasi asli JavaScript: Apakah berperilaku asinkron? Misalnya, jika saya menelepon:
[many many elements].forEach(function () {lots of work to do})
Apakah ini akan non-blocking?
javascript
arrays
asynchronous
foreach
node.js
R. Gr.
sumber
sumber
Jawaban:
Tidak, itu memblokir. Lihat spesifikasi algoritma .
Namun implementasi yang mungkin lebih mudah dipahami diberikan pada MDN :
Jika Anda harus mengeksekusi banyak kode untuk setiap elemen, Anda harus mempertimbangkan untuk menggunakan pendekatan yang berbeda:
dan kemudian menyebutnya dengan:
Ini akan menjadi non-blocking. Contohnya diambil dari JavaScript Kinerja Tinggi .
Pilihan lain mungkin pekerja web .
sumber
forEach
misalnya, tidak memblokirawait
pernyataan dan Anda sebaiknya menggunakanfor
perulangan: stackoverflow.com/questions/37962880/…await
di dalamasync
. TetapiforEach
tidak tahu apa fungsi async. Perlu diingat bahwa fungsi async hanyalah fungsi mengembalikan janji. Apakah Anda berharapforEach
untuk menangani janji yang dikembalikan dari panggilan balik?forEach
sepenuhnya mengabaikan nilai balik dari callback. Itu hanya akan dapat menangani panggilan balik async jika async itu sendiri.Jika Anda memerlukan versi asynchronous-friendly
Array.forEach
dan sejenisnya, mereka tersedia di modul 'async' Node.js: http://github.com/caolan/async ... sebagai bonus modul ini juga berfungsi di browser .sumber
eachSeries
.Ada pola umum untuk melakukan perhitungan yang sangat berat di Node yang mungkin berlaku untuk Anda ...
Node adalah single-threaded (sebagai pilihan desain yang disengaja, lihat Apa itu Node.js? ); ini artinya hanya dapat menggunakan satu inti. Kotak-kotak modern memiliki 8, 16, atau bahkan lebih banyak core, sehingga ini bisa membuat 90% mesin idle. Pola umum untuk layanan REST adalah menjalankan satu proses simpul per inti, dan meletakkannya di belakang penyeimbang beban lokal seperti http://nginx.org/ .
Forking a child - Untuk apa yang Anda coba lakukan, ada pola umum lainnya, yaitu menghentikan proses seorang anak untuk melakukan pekerjaan berat. Keuntungannya adalah proses anak dapat melakukan perhitungan berat di latar belakang sementara proses orang tua Anda responsif terhadap peristiwa lain. Tangkapannya adalah bahwa Anda tidak dapat / tidak boleh berbagi memori dengan proses anak ini (bukan tanpa BANYAK contortions dan beberapa kode asli); Anda harus mengirim pesan. Ini akan bekerja dengan baik jika ukuran input dan output data Anda kecil dibandingkan dengan perhitungan yang harus dilakukan. Anda bahkan dapat menjalankan proses node.js anak dan menggunakan kode yang sama seperti yang Anda gunakan sebelumnya.
Sebagai contoh:
sumber
Array.forEach
dimaksudkan untuk menghitung hal-hal yang tidak menunggu, dan tidak ada yang bisa diperoleh dengan membuat komputasi asinkron dalam suatu peristiwa (pekerja web menambahkan multi-pemrosesan, jika Anda memerlukan komputasi multi-inti). Jika Anda ingin menunggu beberapa tugas berakhir, gunakan penghitung, yang bisa Anda bungkus dalam kelas semaphore.sumber
Sunting 2018-10-11: Sepertinya ada peluang bagus standar yang dijelaskan di bawah ini mungkin tidak dapat dilalui, pertimbangkan perpipaan sebagai alternatif (tidak berperilaku sama persis tetapi metode dapat diimplementasikan di manor serupa).
Inilah tepatnya mengapa saya senang dengan es7, di masa depan Anda akan dapat melakukan sesuatu seperti kode di bawah ini (beberapa spesifikasi tidak lengkap jadi gunakan dengan hati-hati, saya akan mencoba untuk tetap up to date). Tetapi pada dasarnya menggunakan operator :: bind baru, Anda akan dapat menjalankan metode pada objek seolah-olah prototipe objek berisi metode. misalnya [Objek] :: [Metode] di mana biasanya Anda akan memanggil [Objek]. [ObjectsMethod]
Catatan untuk melakukan ini hari ini (24-Juli-16) dan membuatnya bekerja di semua browser Anda perlu mengubah kode Anda untuk fungsionalitas berikut: Impor / Ekspor , fungsi Panah , Janji , Async / Menunggu dan yang paling penting, fungsi bind . Kode di bawah ini dapat dimodifikasi untuk hanya menggunakan fungsi bind jika perlu, semua fungsi ini tersedia dengan rapi saat ini dengan menggunakan babel .
YourCode.js (di mana ' banyak pekerjaan harus dilakukan ' hanya harus mengembalikan janji, menyelesaikannya ketika pekerjaan asinkron dilakukan.)
ArrayExtensions.js
sumber
Ini adalah fungsi asinkron pendek untuk digunakan tanpa memerlukan lib pihak ketiga
sumber
Ada paket di npm untuk asinkron mudah untuk setiap loop .
Juga variasi lain untuk AllAsync
sumber
Dimungkinkan untuk membuat kode bahkan solusi seperti ini misalnya:
Di sisi lain, ini jauh lebih lambat daripada "untuk".
Jika tidak, pustaka Async yang unggul dapat melakukan ini: https://caolan.github.io/async/docs.html#each
sumber
Ini adalah contoh kecil yang bisa Anda jalankan untuk mengujinya:
Ini akan menghasilkan sesuatu seperti ini (jika terlalu sedikit / banyak waktu, tambah / kurangi jumlah iterasi):
sumber
Gunakan Promise.each dari bluebird perpustakaan.
Metode ini mengulangi array, atau janji array, yang berisi janji-janji (atau campuran dari janji-janji dan nilai-nilai) dengan fungsi iterator yang diberikan dengan tanda tangan (nilai, indeks, panjang) di mana nilai adalah nilai yang diselesaikan dari suatu janji masing-masing dalam array input. Iterasi terjadi secara serial. Jika fungsi iterator mengembalikan janji atau janji, maka hasil dari janji tersebut ditunggu sebelum melanjutkan dengan iterasi berikutnya. Jika ada janji dalam array input yang ditolak, maka janji yang dikembalikan juga ditolak.
Jika semua iterasi berhasil diselesaikan, Promise.each memutuskan ke array asli yang tidak dimodifikasi . Namun, jika satu iterasi menolak atau kesalahan, Promise.each segera menghentikan eksekusi dan tidak memproses iterasi lebih lanjut. Kesalahan atau nilai yang ditolak dikembalikan dalam kasus ini alih-alih array asli.
Metode ini dimaksudkan untuk digunakan untuk efek samping.
sumber