Как написать неблокирующую асинхронную функцию в экспресс-обработчике запросов

Все:

Я довольно новичок в асинхронном программировании Node, мне интересно, как мне написать какой-нибудь обработчик экспресс-запросов, который может обрабатывать трудоемкие задачи вычисления без обработки экспресс-блока после запроса?

Я думал, что setTimeout может сделать это, чтобы поместить работу в цикл обработки событий, но он по-прежнему блокирует другие запросы:

var express = require('express');
var router = express.Router();


function heavy(callback){
    setTimeout(callback, 1);
}

router.get('/', function(req, res, next) {
    var callback = function(req, res){
        var loop = +req.query.loop;
        for(var i=0; i<loop; i++){
            for(var j=0; j<loop; j++){}
        }
        res.send("finished task: "+Date.now());
    }.bind(null, req, res);

    heavy(callback)
}); 

Наверное, я не понимал, как работает setTimeout (мое понимание setTimeout заключается в том, что после этой задержки в 1 мс он вызовет обратный вызов в отдельном потоке / процессе, не блокируя другой тяжелый вызов), может кто-нибудь показать мне, как это сделать без блокировки другой запрос к хэви ()?

Спасибо

1 ответ

Вместо setTimeout лучше использовать process.nextTick или setImmediate (в зависимости от того, когда вы хотите, чтобы ваш обратный вызов был запущен). Но недостаточно поместить долго выполняющийся код в функцию, потому что он все равно заблокирует ваш поток, всего через миллисекунду.

Вам нужно сломать ваш код и запустить setImmediate или process.nextTick несколько раз - как в каждой итерации, а затем запланировать новую итерацию из этого. В противном случае вы ничего не получите.

пример

Вместо такого кода:

var a = 0, b = 10000000;

function numbers() {
  while (a < b) {
    console.log("Number " + a++);
  }
}

numbers();

Вы можете использовать такой код:

var a = 0, b = 10000000;

function numbers() {
  var i = 0;
  while (a < b && i++ < 100) {
    console.log("Number " + a++);
  }
  if (a < b) setImmediate(numbers);
}

numbers();

Первый из них заблокирует ваш поток (и, вероятно, переполнит ваш стек вызовов), а второй не заблокирует (или, точнее, он заблокирует ваш поток 10000000 раз на очень короткий момент, позволяя другим вещам выполняться между этими моментами).

Вы также можете подумать о порождении внешнего процесса или написании собственного дополнения в C/C++, где вы можете использовать потоки.

Для получения дополнительной информации см.:

Другие вопросы по тегам