Щоб зрозуміти, що відбувається напевно, мені потрібно було внести деякі зміни у ваш сценарій, але тут є.
По-перше, ви можете знати, як node
і як це event loop
працює, але дозвольте мені зробити короткий підсумок. Коли ви запускаєте скрипт, node
час виконання спочатку запускає його синхронну частину, потім планує promises
і timers
виконувати наступні цикли, а після перевірки вони вирішуються, запустіть зворотні виклики в іншому циклі. Цей простий суть пояснює це дуже добре, кредит @StephenGrider:
const pendingTimers = [];
const pendingOSTasks = [];
const pendingOperations = [];
// New timers, tasks, operations are recorded from myFile running
myFile.runContents();
function shouldContinue() {
// Check one: Any pending setTimeout, setInterval, setImmediate?
// Check two: Any pending OS tasks? (Like server listening to port)
// Check three: Any pending long running operations? (Like fs module)
return (
pendingTimers.length || pendingOSTasks.length || pendingOperations.length
);
}
// Entire body executes in one 'tick'
while (shouldContinue()) {
// 1) Node looks at pendingTimers and sees if any functions
// are ready to be called. setTimeout, setInterval
// 2) Node looks at pendingOSTasks and pendingOperations
// and calls relevant callbacks
// 3) Pause execution. Continue when...
// - a new pendingOSTask is done
// - a new pendingOperation is done
// - a timer is about to complete
// 4) Look at pendingTimers. Call any setImmediate
// 5) Handle any 'close' events
}
// exit back to terminal
Зауважте, що цикл подій ніколи не закінчиться, поки не очікують завдання ОС. Іншими словами, виконання вашого вузла ніколи не закінчиться, поки не буде очікуваних HTTP-запитів.
У вашому випадку вона виконує async
функцію, оскільки вона завжди повертає обіцянку, вона планує її виконання на наступній ітерації циклу. У функції асинхронізації ви плануєте одразу 1000 обіцянок (HTTP-запитів) у цій map
ітерації. Після цього ви очікуєте, що тоді все вирішите закінчити програму. Це буде точно працювати, якщо тільки ваша анонімна стрілка не функціонуєmap
не помилок . Якщо одне з ваших обіцянок видає помилку, і ви не впораєтеся з нею, деякі з обіцянок не матимуть зворотного виклику, коли колись програма буде завершена, але не вийде , тому що цикл подій не дозволить їй вийти, поки не вирішиться всі завдання, навіть без зворотного дзвінка. Як говориться наPromise.all
Документи : вона буде відхилена, як тільки відхилиться перша обіцянка.
Отже, ваша ECONNRESET
помилка не пов’язана з самим вузлом, це щось із вашою мережею, що змусило завантажувати помилку, а потім запобігти закінченню циклу подій. За допомогою цього невеликого виправлення ви зможете побачити всі запити, які вирішуються асинхронно:
const fetch = require("node-fetch");
(async () => {
try {
const promises = Array(1000)
.fill(1)
.map(async (_value, index) => {
try {
const url = "https://google.com/";
const response = await fetch(url);
console.log(index, response.statusText);
return response;
} catch (e) {
console.error(index, e.message);
}
});
await Promise.all(promises);
} catch (e) {
console.error(e);
} finally {
console.log("Done");
}
})();
npx envinfo
, запустивши свій приклад у моєму сценарії Win 10 / nodev10.16.0 закінчується в 8432.805ms