Понимание цикла событий Node.js. process.nextTick() никогда не вызывается. Зачем?

Я экспериментирую с циклом событий. Сначала я начинаю с этого простого кода, чтобы прочитать и распечатать содержимое файла:

var fs = require('fs');
var PATH = "./.gitignore";

fs.readFile(PATH,"utf-8",function(err,text){
    console.log("----read: "+text);
});

Затем я помещаю его в бесконечный цикл. В этом случае функция readFile никогда не выполняется. Если я не ошибаюсь, потому что Node один поток занят итерацией, не допуская выполнения вызовов ввода/вывода.

while(true){
    var fs = require('fs');
    var PATH = "./.gitignore";

    fs.readFile(PATH,"utf-8",function(err,text){
        console.log("----read: "+text);
    });
}

Итак, я хотел бы сделать что-то, чтобы вызовам ввода-вывода назначалось время процесса, переплетенное с циклом. Я пробовал с process.nextTick(), но он не работает:

while(true){
    process.nextTick(function(){
        fs.readFile(PATH,"utf-8",function(err,text){
            console.log("----read: "+text)
        });
    });
}

Почему это не работает и как я могу это сделать?

Ответ 1

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

Когда вы работаете с асинхронным кодом, ваши обычные циклы и структуры управления, как правило, вас заправляют. Причина в том, что они выполняются синхронно за один шаг цикла событий. Пока что-то не произойдет, что снова приведет к управлению циклом событий, ничего не произойдет "nextTick".

Подумайте об этом так: вы находитесь в Pass B цикла событий, когда ваш код работает. Когда вы вызываете

process.nextTick(function foo() { do.stuff(); })' 

вы добавляете foo в список "вещей, которые нужно сделать, прежде чем вы начнете передавать C цикла событий". Каждый раз, когда вы вызываете nextTick, вы добавляете еще одну вещь в список, но никто из них не будет работать до тех пор, пока не будет выполнен синхронный код.

Вместо этого вам нужно создать ссылки "сделать следующую вещь" в ваших обратных вызовах. Думайте о связанных списках.

// var files = your list of files;
function do_read(count) {
     var next = count+1;
     fs.readFile(files[count], "utf-8", function(err,text) {
         console.log("----read: " + text);

         if (next < files.length) {
            // this doesn't run until the previous readFile completes.
            process.nextTick(function() { do_read(next) });
         }
     });
}
// kick off the first one:
do_read(files[0], 0);

(очевидно, это надуманный пример, но вы получаете идею)

Это приводит к тому, что каждый "следующий файл" добавляется в очередь "nextTick" для работы только после того, как предыдущая была полностью обработана.

TL; DR: Большую часть времени вы не хотите запускать его, делая следующую вещь, пока предыдущая вещь не будет завершена.

Надеюсь, что это поможет!