setImmediate()
и setTimeout()
могут казаться чем-то асинхронным, потому что они не блокируют сразу, но на самом деле они не решают проблему длительных задач блокировки. Они планируют выполнение задач позже, но когда они будут запущены, это будет продолжительная задача, которая блокирует цикл обработки событий до его завершения. Итак, ваша makeItAsync()
функция действительно не более полезна, чем просто запуск оригинальной функции с setTimeout()
.
Если у вас длинная задача и вы не хотите слишком долго блокировать цикл обработки событий, это ваши основные параметры:
Разбейте длительные задачи на очень маленькие части работы, каждая из которых может быть выполнена за несколько миллисекунд. После того, как вы закончите одну часть работы, запланируйте следующую часть работы с коротким setTimeout()
, и это позволит циклу обработки событий обрабатывать другие события между вашими работами. Обычно для этого требуется переписать долгосрочную задачу (почти в конечный автомат), а иногда ее сложно спроектировать и поддерживать для некоторых типов обработки.
Запустите дочерний процесс и отправьте долгосрочную задачу дочернему процессу. Тогда ваш главный цикл обработки событий полностью свободен от длительных задач. Дочерний процесс может просто сообщить результат, когда это будет сделано. Если вам приходится многократно выполнять эту задачу, вы можете создать рабочую очередь и набор дочерних процессов, которые будут работать с задачами в очереди, отправляя сообщение родителю, когда они будут выполнены. Это обычно довольно легко сделать. Как только недостатком является то, что дочерний процесс не имеет прямого доступа к данным в основном процессе, поэтому, если долго выполняющимся задачам требуется доступ к большому количеству данных из основного процесса, то вам необходимо разработать способ совместного использования данных (возможно, помещать данные в другой процесс, например, в redis, где к нему могут обращаться несколько процессов).