Pertanyaannya adalah apa yang sebenarnya terjadi ketika Anda memicu permintaan HTTP keluar 1k-2k? Saya melihat bahwa itu akan menyelesaikan semua koneksi dengan mudah dengan 500 koneksi tetapi bergerak ke atas dari sana tampaknya menyebabkan masalah karena koneksi dibiarkan terbuka dan aplikasi Node akan macet di sana. Diuji dengan server lokal + contoh Google dan server tiruan lainnya.
Jadi dengan beberapa titik akhir server yang berbeda saya memang menerima alasan: baca ECONNRESET yang baik-baik saja server tidak dapat menangani permintaan dan melemparkan kesalahan. Dalam rentang permintaan 1k-2k program hanya akan hang. Ketika Anda memeriksa koneksi terbuka dengan lsof -r 2 -i -a
Anda bisa melihat bahwa ada beberapa jumlah koneksi X yang terus menggantung di sana 0t0 TCP 192.168.0.20:54831->lk-in-f100.1e100.net:https (ESTABLISHED)
. Ketika Anda menambahkan pengaturan batas waktu ke permintaan, ini mungkin akan berakhir dengan kesalahan batas waktu, tetapi mengapa jika koneksi tidak terputus selamanya dan program utama akan berakhir dalam keadaan limbo?
Kode contoh:
import fetch from 'node-fetch';
(async () => {
const promises = Array(1000).fill(1).map(async (_value, index) => {
const url = 'https://google.com';
const response = await fetch(url, {
// timeout: 15e3,
// headers: { Connection: 'keep-alive' }
});
if (response.statusText !== 'OK') {
console.log('No ok received', index);
}
return response;
})
try {
await Promise.all(promises);
} catch (e) {
console.error(e);
}
console.log('Done');
})();
sumber
npx envinfo
, menjalankan contoh Anda pada skrip Win 10 / nodev10.16.0 saya berakhir di 8432.805msJawaban:
Untuk memahami apa yang terjadi dengan pasti, saya perlu membuat beberapa modifikasi pada skrip Anda, tetapi di sini ada.
Pertama, Anda mungkin tahu cara
node
danevent loop
kerjanya, tetapi izinkan saya membuat rekap cepat. Saat Anda menjalankan skrip,node
runtime pertama kali menjalankan bagian sinkronnya kemudian menjadwalkanpromises
dantimers
untuk dieksekusi pada loop berikutnya, dan ketika diperiksa mereka diselesaikan, jalankan callback di loop lain. Intisari sederhana ini menjelaskan dengan sangat baik, kredit ke @StephenGrider:Dalam kasus Anda, ini menjalankan
async
fungsi, karena ia akan selalu mengembalikan janji, itu akan menjadwalkannya untuk dieksekusi dalam iterasi loop berikutnya. Pada fungsi async Anda, Anda menjadwalkan 1000 janji lain (permintaan HTTP) sekaligus dalammap
iterasi itu. Setelah itu, Anda menunggu semuanya diselesaikan untuk menyelesaikan program. Ini akan bekerja, pasti, kecuali fungsi panah anonim Anda padamap
tidak membuang kesalahan . Jika salah satu janji Anda membuat kesalahan dan Anda tidak menanganinya, beberapa janji tidak akan membuat panggilan baliknya pernah membuat program untuk mengakhiri tetapi tidak untuk keluar , karena loop acara akan mencegahnya untuk keluar sampai diselesaikan semua tugas, bahkan tanpa panggilan balik. Seperti yang tertulis diPromise.all
docs : itu akan menolak segera setelah janji pertama ditolak.Jadi,
ECONNRESET
kesalahan Anda tidak terkait dengan node itu sendiri, adalah sesuatu dengan jaringan Anda yang membuat pengambilan untuk melempar kesalahan dan kemudian mencegah event loop berakhir. Dengan perbaikan kecil ini, Anda dapat melihat semua permintaan diselesaikan secara tidak sinkron:sumber