Node.js sleep, usleep, msleep

Как затормозить поток и сделать паузу

Очень частый вопрос, особенно от тех, кто пришел в мир JS из других языков. Этот вопрос встречал даже на собеседованиях. В разных языках программирования и даже в Bash есть такие функции как sleep, usleep и другие. Прямо из коробки. Удобно.

Что делают ясно из названия (или мануала). Sleep — тормозит выполнение потока на время в секундах, а usleep в микросекундах.

В PHP это делается функцией sleep, которая в глобальной области:

<?php sleep(1); # Time in seconds.

В Python нужно заимпортить модуль time:

from time import sleep
sleep(1) # Time in seconds.

В bash все просто, в системе есть программа /usr/bin/sleep:

$ sleep 1

А как быть в Node.js?

А зачем? Это нужно бывает в скриптах разного рода и при отладке, когда вы хотите глазками проследить за логом данных. Конечно же не для серверных приложений. Ни в коем случае! Упаси вас от лукавого блокировать поток выполнения.

Так вот вопрос, как блокировать, если не залезать в NPM и не скачивать готовый модуль? Да все, в принципе, просто.

Пишем функцию sleep

const exec = require('child_process').execSync;
const sleep = time => (
(time = parseInt(time)),
(time > 0
? exec(`sleep ${time}`)
: null
)
);

Ну вот и все. Мы синхронно вызываем команду sleep из системы. По такому же принципу можно вызвать и usleep.

Пишем функцию usleep

Эта функция принимает значения в микросекундах.

1 секунда = 1 000 000 микросекунд.

const exec = require('child_process').execSync;
const usleep = time => (
(time = parseInt(time)),
(time > 0
? exec(`usleep ${time}`)
: null
)
);
usleep(1e6); // Timeout 1 second

Пишем функцию msleep на Atomics.wait

Функцию msleep обычно не вкладывают в ЯП и ее нет в Bash, так как если есть usleep, то можно затормозить на нужное число милисекунд и msleep не нужна. Но мы ее напишем на чистом ванильном JS используя новую крутую фичу Atomics. А точнее заиспользуем метод wait.

Atomics.wait() — проверяет, содержится ли в указанной позиции массива представленное значение. Если нет, то находится в ожидании. Возвращает "ok", "not-equal"или "timed-out". Если ожидание не разрешено в вызывающем агенте, тогда выбросит исключение. Большинство браузеров не разрешают Atomics.wait в главном потоке браузера!

Atomics.wait() моделируется на основе futexes (“fast user-space mutex” — быстрый мьютекс пользовательского пространства) Linux и представляют собой способы ожидания момента, когда определенное состояние не станет true, и обычно используется как блокирующие конструкции.

Так вот, мы можем написать нативную функцию блокировки потока используя этот метод и немного магии:

const msleep = milliSeconds =>
Atomics.wait(
new Int32Array(new SharedArrayBuffer(4)),
0, 0, miliSeconds
)
;

Больше про атомики можно узнать в документации на MDN.

Async/await msleep

Если у вас асинхронный код и вы используете async/await стиль, то вам для дебага (и не только) можно использовать простую реализацию msleep:

const msleep = time =>
new
Promise(
resolve => setTimeout(_=>resolve(), time)
)
;

И тогда вы можете ее использовать в контексте async:

void async function(){
let i = 10;
do {
console.log(`Debug log ${i}`);
await msleep(1000);
}
while(i-->0)
}();

Такой вот вышел небольшой ЛикБез по тормозящим функциям в Node.js.

Готовый код Node.js модуля можно посмотреть на гитхабе по ссылке:


Интересные вакансии связанные с JS, Frontend, Backend и не только можно найти на нашем сайте vacancy.new.hr