Node.js событие l oop игнорирует setTimeout внутри событий чтения потока данных? - PullRequest
0 голосов
/ 15 марта 2020

Я проясняю мои сомнения относительно того, как Node.js выполняет таймеры. Обычно, когда в сценарии узла есть блок setTimeout, событие l oop, даже если у него нет ничего, будет ожидать указанные миллисекунды в setTimeout и завершится после выполнения обратного вызова.

Но рассмотрим ниже code

const fs = require('fs');

let readable = fs.createReadStream('large.csv');
readable.on('data', async chunk => {
    let rows = parseCsvRow(chunk);  
    try {
        for (let i = 0; i < rows.length; i++) {
            console.log(i);
            await someAsyncOperation(rows[i]);
        }
    } catch (error) {
        //something went wrong
    }
});

readable.on('end', chunk => {
    console.log('csv file processed successfully');
});

function someAsyncOperation(){
    return new Promise((resolve, reject) => {
        setTimeout(resolve, 2000);
    });
}

Файл CSV, который я читаю, содержит около 300 строк, и я запускаю запрос ajax для каждого (код скрыт для простоты), выполнение которого занимает около 100 мс, и я смоделировал его здесь, используя a setTimeout.

Когда я запускаю вышеуказанную программу, она почти мгновенно завершает работу, не дожидаясь успешного завершения всех ожидающих таймеров setTimeout. Только потому, что таймеры были запланированы изнутри события data в потоке чтения, событие l oop игнорирует его? Не следует ли ждать, пока все таймеры будут запущены?

Примечание. Я понимаю, что приведенный выше код не является правильным способом выполнения того, что я делаю, но это всего лишь пример, демонстрирующий концепцию, с которой я сталкиваюсь время понимания.

Ответы [ 2 ]

1 голос
/ 15 марта 2020

Это не имеет ничего общего с Node.js или событием l oop.

Проблема в том, что вы передаете функцию async во что-то, что ничего не будет делать с обещай, что вернется. Это одно из обещанных антипаттернов. Используйте async функции в качестве обратных вызовов только тогда, когда одна из них верна:

  • Объект, выполняющий обратный вызов, будет использовать или возвращать обещание (например, Promise.all, потому что он их использует, или map для массивов, потому что он их возвращает)
  • Вам все равно, если вещь, вызывающая вашу функцию async, продолжит работать, в то время как ваша функция async может быть приостановлена ​​на await, и Вы оборачиваете все в функции async в try / catch, который обрабатывает отклонения.

Часть Node.js Speci c: Если вы хотите предотвратить дальнейшее вызывает ваш обработчик data, пока вы не закончите что-то делать, вам нужно pause потока, а затем resume позже.

0 голосов
/ 15 марта 2020

Как и в большинстве случаев, моя путаница произошла из-за опечатки в моем примере кода.

Это была опечатка в моем коде, из-за которой в someAsyncFunction произошла необработанная ошибка. Эта необработанная ошибка заставила узел выйти из программы. Я исправил это, и теперь он работает как ожидалось. Текущий код, как показано в описании вопроса, корректно ожидает выполнения таймеров до того, как узел выйдет из процесса.

TL; DR - Узел будет ожидать выполнения всех таймеров перед выходом из процесса. Не имеет значения, установлены ли таймеры из обратных вызовов событий или любого другого места в этом отношении (также у вас не должно быть никаких необъяснимых ошибок)

...