Memahami Cara Pilihan Gelung Mempengaruhi Prestasi Tak Segerak
Dalam projek saya baru-baru ini, saya perlu mengemas kini sejumlah besar rekod dalam pangkalan data NoSQL — lebih seribu. Memandangkan mengemas kini kesemuanya sekali gus tidak boleh dilaksanakan dan prosesnya juga tidak segerak, saya memutuskan untuk memprosesnya dalam kelompok yang lebih kecil iaitu 20 rekod setiap satu. Saya melaksanakan ini dalam gelung menggunakan forEach, di mana setiap set 20 akan dikemas kini sebelum beralih ke set seterusnya. Walau bagaimanapun, selepas mempraktikkan pendekatan ini, saya mendapati bahawa tidak semua rekod dikemas kini seperti yang dijangkakan, walaupun dalam kelompok yang lebih kecil ini. Sebagai contoh, apabila saya cuba mengemas kini kumpulan 25 rekod, hanya 10 yang berjaya dikemas kini. Tiada log untuk 10 rekod lain dan bilangan rekod yang gagal dikemas kini berbeza-beza secara rawak — kadangkala 12, kadangkala 5 atau kadangkala 7.
Setelah penyahpepijatan selanjutnya, saya mendapati bahawa rekod ini berkemungkinan besar akan dilangkau semasa proses kemas kini. Sekarang, mengapa ini berlaku? Mari terokai isu ini untuk memahami gelagat dan mengenal pasti sebab yang berpotensi di sebalik isu ini.
Masalah
Selepas beberapa penyelidikan, saya mendapati bahawa menggunakan fungsi tak segerak di dalam gelung forEach tanpa mekanisme yang betul untuk menunggu semua lelaran boleh membawa kepada masalah. Dalam kes ini, kami menggunakan async/waiit dalam gelung forEach tanpa memastikan bahawa semua lelaran telah ditunggu (lihat kod di bawah):
async function patchRecords(records) { // Here, the length of records is 25 let successfulUpdates = 0; // Initialize a counter for successful updates records.forEach(async (item) => { await databaseName.patch(item); successfulUpdates++; // Increment counter on successful update }); // Return the number of records updated successfully return successfulUpdates; } const response = await patchRecords(records); // Make sure to await this call
Dalam kod di atas, tiada mekanisme untuk memastikan semua lelaran tak segerak bagi gelung selesai. Kaedah forEach melancarkan berbilang panggilan tak segeraks untuk menampal rekod, tetapi patchRecords berfungsi dengan cepat mencapai pernyataan pulangan tanpa menunggu tampungan tersebut selesai. Akibatnya, semasa kemas kini diproses di latar belakang, fungsi itu bergerak tanpa menunggunya selesai. Ini boleh menyebabkan beberapa janji yang belum selesai tidak ditunaikan, yang boleh menyebabkan kemas kini dilangkau atau dibuang.
Penyelesaian
Jadi bagaimana kita boleh menyelesaikannya? Sebelum kita beralih ke penyelesaian, mari kita fahami cara berbeza untuk mengulang data. Pada asasnya, terdapat dua pendekatan: Mengulangi data berurutan atau dalam selari.
Jika anda ingin mengulangi data secara tidak segerak secara berurutan, menggunakan gelung forEach boleh membawa kepada isu yang kami bincangkan. Sebaliknya, lebih baik menggunakan gelung untuk…dari moden atau untuk gelung yang ringkas, kerana ini membolehkan menunggu berfungsi dengan baik dan memastikan semua kemas kini diproses tanpa dilangkau (lihat kod di bawah).
async function patchRecords(records) { // Here, the length of records is 25 let successfulUpdates = 0; // Initialize a counter for successful updates records.forEach(async (item) => { await databaseName.patch(item); successfulUpdates++; // Increment counter on successful update }); // Return the number of records updated successfully return successfulUpdates; } const response = await patchRecords(records); // Make sure to await this call
Sebaliknya, jika anda ingin memproses rekod secara selari, sekali lagi menggunakan forEach tidak akan berfungsi. Walaupun setiap panggilan balik tak segerak memulangkan janji, beberapa janji tersebut mungkin kekal tidak ditunaikan kerana ia tidak ditunggu-tunggu. Sebaliknya, gunakan peta untuk menjana pelbagai janji dan kemudian tunggu dengan Promise.all (lihat kod di bawah).
async function patchRecords(records) { let successfulUpdates = 0; // Counter for successful updates for (const item of records) { try { // Query to patch each record await databaseName.patch(item); successfulUpdates++; // Increment counter on success } catch { // Handle any errors } } return successfulUpdates; // Return the number of records updated successfully } const response = await patchRecords(records); // Make sure to await this call
Ini menunjukkan cara memilih kaedah gelung yang betul boleh memberi kesan besar kepada hasil yang dijangkakan bagi operasi tak segerak anda. Jenis gelung yang anda gunakan — sama ada forEach, for…of, atau standard for loop — memainkan peranan penting dalam sejauh mana kod anda mengurus tugas tak segerak.
Pengakhiran
Adakah saya menerangkan perkara dengan jelas? beritahu saya dalam ulasan di bawah.
Saya seronok berkongsi pengalaman saya, dan saya harap anda mendapati pengalaman itu juga berharga! Memandangkan saya masih meneroka ruang ini, saya amat menyukai maklum balas dan cadangan anda. ☺️ Jika anda melihat kawasan yang boleh saya perbaiki, atau mempunyai topik yang anda ingin saya sampaikan, jangan teragak-agak untuk menghubungi kami! ? laman web. Saya teruja untuk belajar dan berkembang dengan bantuan anda. ??
Atas ialah kandungan terperinci forEach vs. for: The Asynchronous Showdown!. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!