There is no built-in JavaScript sleep function, which is a problem when you want to delay or pause code execution.
You can achieve a similar effect in JavaScript with loops (do while
/ while
/ for
), setTimeout()
, and Promises!
Use these 7 code examples to pause()
, delay()
, and revoke()
JS code
What is the JavaScript Sleep Function?
Many programming languages (C, C++, C#, Python, PHP, Ruby, Java) have a function to delay or pause the execution of a code!
For example, wait for a few seconds before running a function
function myFunction(time) { console.log('Time starts!'); // Command to make JS wait before continuing sleep(1000) console.log('Time is up!'); }
JavaScript V8 engine does not support direct sleeping because it uses a single thread to handle (multiple) tasks and executes on one main thread.
Sleeping COULD work against JS nature, forcing the whole thread on which JavaScript is running to pause.
Blocking any operation with a sleep()
function (which stops the whole thread) is counterproductive in a JavaScript “asynchronous” environment. We want to manage tasks simultaneously with its event-driven and non-blocking design.
Although there isn’t a native sleep function in JavaScript, we still need its functionality in some cases and need other techniques WITHOUT blocking the thread
1 The Easiest JavaScipt Sleep with setTimeout
JS also offers functions setTimeout()
and setInterval()
to create time intervals in the event loop.
setTimeout (part of the DOM API) lets you schedule events or functions for some time in the future.
Neither window.setTimeout nor window.setInterval blocks other scripts (including the main thread), which is perfect for asynchronous operations.
Move the block of code that needs to run after a pause into the callback (anonymous callback function) for the setTimeout()
// Code before the pause setTimeout(function() { // Code to run after the pause }, 2000);
This approach will not put a stop to the execution of your scripts. The asynchrony nature of setTimeout() allows JavaScript to execute the rest of the code, awaiting the delay to complete
console.log("Printed Firsted"); setTimeout(function() { console.log("Printed Third"); }, 2000); console.log("Printed Second");
Note that the console.log(“Printed Third”) prints at the end of the output, which shows that setTimeout() does not block the main thread, allowing the JS to print the third console.log(“Printed Second”).
Note: Using setTimeout(function(){}, 0)
is not equivalent to executing the function immediately after 0ms. JS is queuing the function to execute after the current call stack is empty (useful when you want to defer the code).
If you need to cancel a timeout before it runs, save the timeoutID and then call window.clearTimeout
const timeoutID = setTimeout(function() { console.log("This will not run if cleared"); }, 2000); clearTimeout(timeoutID); // Clears the timeout
clearTimeout
cancels the timeout using the timeoutID
.
My code sandbox creates two buttons: “Start” and “Clear. Clicking “Start” sets a two seconds timeout that logs a message to the console — “Clear” cancels this timeout.
2 Scheduling Async Function With Nested setTimeout() And then() Method
setTimeout() allows you to execute a particular piece of code after the lapse of a particular time (useful for scheduling heavy computations or rendering).
function someComputationOrRender1() { console.log("First computation or render"); } function someComputationOrRender2() { console.log("Second computation or render"); } someComputationOrRender1(); setTimeout(function() { someComputationOrRender2(); }, 1000);
someComputationOrRender2 happens one second after someComputationOrRender1.
The good thing about the sleep function is that you can return absolutely any then-like object. This might let you simplify your code even more:
const sleep = (t) => ({ then: (resolve) => setTimeout(resolve, t) }); const someMethod = async () => { console.log("hi"); await sleep(5000); // Pause for 5 seconds console.log("bye"); }; someMethod();
The button click prints “hi,” wait for 5 seconds, and then prints “bye.”
How JS Executes Asynchronous setTimeout
The event loop is what runs the heart of JavaScript’s concurrency model. It runs the code, collects and processes events, and executes queued sub-tasks.
When you call setTimeout(callback, delay), the JavaScript adds the callback function to the event queue after the delay time in milliseconds.
The callback function does not run exactly after the delay you specify but only becomes eligible for JS to execute it. JavaScript simply places the callback into an event queue to wait for its turn to go to the Event loop.
Event loop processes and runs tasks in the order they come – First In, First Out (FIFO).
The main thread checks up on the event queue, and If your callback is first on the queue and the main thread is idle, it will pick it up and run it.
3 Do While Loops That Stop JS Execution — pausecomp (Not Recommended)
Some devs want to achieve a Javascript sleep function that pauses execution rather than delaying a code function.
A busy wait loop simply runs until we want to pause (pausecomp method), which is generally a horrible idea for production
function sleep(milliseconds) { const start = new Date().getTime(); for (var i = 0; i < 1e7; i++) { if ((new Date().getTime() - start) > milliseconds) { break; } } } // To sleep for 1 second sleep(1000);
It keeps your script busy for milliseconds, freezing every other JavaScript code function. Depending on the browser, busy wait loops make the page (and potentially the whole browser) completely unresponsive.
Placing a busy-wait loop for longer than a few seconds causes the browser to throw warnings
“A script on this page may be busy, or it may have stopped responding. You can stop the script now, open the script in the debugger, or let the script continue.”
Best Practices — Why Not Sleep With Do / While Loops?
Do/while
loop for a sleep function in JavaScript comes with issues and (in general) is a BAD practice. Here’s why
- Busy-wait loops freeze the browser with every code execution until the loop and suspend other JS or UI updates
- Unresponsive UI and poor UX irritate users
- Because busy-wait loops are high-processor-consuming, they take up too many resources (CPU memory)
- Blocking sleep functions creates possible deadlocks (and race conditions), where two pieces of code are trying to sleep, becoming very messy and hard to debug
4 Get Rid Of Nested setTimeouts — Add Promise
Long chains of setTimeout
, when you nest sleep()
calls inside other, make your JavaScript difficult to read and maintain. Flattening your code with Promises
is much better
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
That sleep function returns a Promise, which resolves after the ms milliseconds. You can use it in an async/await syntax
async function myFunction() { console.log("Start computation or render 1") await sleep(1000) // Wait 1 second console.log("Carry out computation or render 2") await sleep(1000) // Wait for another 1 second console.log("Finish with computation or render 3") } myFunction()
You can even add a sleep function to the Function prototype for global use
Function.prototype.sleep = function(delay, ...args) { setTimeout(() => this(...args), delay); }; // Usage console.log.sleep(2000, 'Hello, World!!')
For TypeScript, you have to define the sleep
function using type annotations (Read my post with Full Guide To TypeScript Record Type)
const sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms))
Using sleep()
with Promises
is still asynchronous—it does not block the event loop, and other work continues while counting down the delay.
5 Loop Through Array And Await Pause Each Iteration
You should wait for each operation to finish before proceeding to the next. Array.map()
and asynchronous operations result in incorrect behavior since map() does not wait
const sleep = m => new Promise(r => setTimeout(r, m)) const letters = ['a', 'b', 'c', 'd']; letters.map(async (letter) => { await sleep(1000) console.log(letter) });
All console.logs print after a 1-second delay, but at the SAME time. This is because the Array.map() runs each of those async operations simultaneously.
Instead, do the same with a for…of loop
const letters = ['a', 'b', 'c', 'd'] for (const letter of letters) { await sleep(1000) console.log(letter) }
In this example, every console.log
prints out after a 2-second delay, one after the other. This is because the for…of loop ensures the code (synchronous) pauses at the sleep function until the next iteration takes place.
6 How To Abort A Sleep Based On Promise
You’ll probably find yourself in a situation where you want to cancel the sleep before the timeout finishes.
A simple version of a sleep function returns a promise delay with an extra method to abort it if you need it
function sleep(ms){ let timeoutId; let copyReject; const promise = new Promise((resolve, reject) => { copyReject = reject; timeoutId = setTimeout(() => { resolve(); }, ms); }); promise.abort = function(){ clearTimeout(timeoutId); copyReject('Aborted!'); }; return promise; }
The sleep function creates a promise that includes an abort method to reject the promise before JS resolves it.
const thisAborts = delay(2000); const thisNotAborts = delay(2000); thisAborts .then(() => console.log('thisAborts succeed')) .catch(console.error); thisNotAborts .then(() => console.log('thisNotAborts succeed')) .catch(console.error); setTimeout(() => thisAborts.abort(), 1000);
JavaScript will reject thisAborts after 1 second (because I manually abort()
it), and thisNotAborts resolves successfully after 2 seconds.
7 Abort Sleep Function In JavaScript With Signal
Implement an abortable sleep using the AbortSignal
part of Web APIs (AbortControllers is not ECMAScript, tho Node.js supports it) that has been around for a while (2017, IIRC).
This sleep function returns the promise after the ms (milliseconds) delay, and AbortSignal handles early termination
function sleep(ms, signal) { return new Promise((resolve, reject) => { if (signal.aborted) { return reject(new Error("aborted")); } const timeout = setTimeout(() => { resolve(); signal.removeEventListener('abort', onAbort); }, ms); const onAbort = () => { clearTimeout(timeout); reject(new Error("aborted")); }; signal.addEventListener('abort', onAbort); }); }
I register onAbort() as an event listener for the abort event on the signal. If you abort AbortSignal during the delay, JS rejects the promise and clears the timeout.
// Usage const controller = new AbortController(); sleep(9000, controller.signal) .then(() => console.log('Finished sleeping')) .catch(err => { if (err.message !== "aborted") throw err; console.log('Cancelled sleep before it completed'); }); // To bring an end to the sleep setTimeout(() => controller.abort(), 1000);
I use a setTimeout to call controller.abort()
after 1000 milliseconds (1 second), which triggers the abort event on the signal. This will cause the onAbort function to clean the timeout and reject the promise with an “aborted” error.
TypeScript Sleep Version With Signal And Abort
export function sleep(ms: number, options: { signal?: AbortSignal } = {}) { const { signal } = options; return new Promise<void>((resolve, reject) => { if (signal?.aborted) { return reject(signal.reason); } const id = setTimeout(() => { resolve(); signal?.removeEventListener('abort', abort); }, ms); const abort = () => { clearTimeout(id); reject(signal.reason); }; signal?.addEventListener('abort', abort); }); }
(Read my post with Best TypeScript Generics Tutorial)
Conclusion: Use setTimeout In JavaScript Version Of Sleep
While JS lacks a built-in sleep function, these 7 examples show how to pause(), delay(), and abort() (revoke) code execution in JavaScript.
In the future, add error handling to manage different types of errors that occur during the wait period.
Or extend the sleep() function to support a retry mechanism allowing the retry of the operation N a number of times if JS aborts the sleep()