- Key Takaways
- How to Create a Sleep Function in JavaScript
- Understanding JavaScript’s Execution Model
- How to Use SetTimeout in JavaScript Properly
- setTimeout() Function Examining and Best Practices
- Increasing Timeouts as Alternative to Sleep Function in JavaScript
- Flow Control in Modern JavaScript
- Bringing Sleep to Native JavaScript
- How to Write Better Sleep Function in JavaScript
- Best Practices for Creating a JavaScript Sleep Function
- Conclusion
- FAQs About Sleep, Pause & Wait Functions in JavaScript
Many programming languages have a sleep
function that will delay a program’s execution for a given number of seconds. JavaScript lacks this built-in feature, but not to worry. In this article, we’ll explore various techniques to implement delays in your JavaScript code, keeping in mind the language’s asynchronous nature.
Key Takaways
How to Create a Sleep Function in JavaScript
For those of you who are here for a quick fix and don’t want to dive into the technical details, we’ve got you covered. Here’s the most straightforward way to add a sleep function to your JavaScript toolbox:
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
console.log('Hello');
sleep(2000).then(() => { console.log('World!'); });
Run this code, and you’ll see “Hello” pop up in your console. Then, after a brief two-second pause, “World!” will follow. It’s a neat and effective way to introduce a delay without breaking a sweat.
If this is all you came for, fantastic! But if you’re curious about the “why” and the “how”, there’s more to learn. There are nuances and intricacies in dealing with time in JavaScript that you might find useful. So, read on to find out more!
Understanding JavaScript’s Execution Model
Now that we’ve got a quick solution under our belts, let’s delve into the mechanics of JavaScript’s execution model. Understanding this is crucial for effectively managing time and asynchronous operations in your code.
Consider the following Ruby code:
require 'net/http'
require 'json'
url = 'https://api.github.com/users/jameshibbard'
uri = URI(url)
response = JSON.parse(Net::HTTP.get(uri))
puts response['public_repos']
puts 'Hello!'
As one might expect, this code makes a request to the GitHub API to fetch my user data. It then parses the response, outputs the number of public repos attributed to my GitHub account and finally prints “Hello!” to the screen. Execution goes from top to bottom.
Contrast that with the equivalent JavaScript version:
fetch('https://api.github.com/users/jameshibbard')
.then(res => res.json())
.then(json => console.log(json.public_repos));
console.log('Hello!');
If you run this code, it will output “Hello!” to the screen, then the number of public repos attributed to my GitHub account.
This is because fetching data from an API is an asynchronous operation in JavaScript. The JavaScript interpreter will encounter the fetch
command and dispatch the request. It will not, however, wait for the request to complete. Rather, it will continue on its way, output “Hello!” to the console, and then when the request returns a couple of hundred milliseconds later, it will output the number of repos.
If any of this is news to you, you should watch this excellent conference talk: What the heck is the event loop anyway?
How to Use SetTimeout in JavaScript Properly
Now that we have a better understanding of JavaScript’s execution model, let’s have a look at how JavaScript handles delays and asynchronous code.
The standard way of creating a delay in JavaScript is to use its setTimeout
method. For example:
console.log('Hello');
setTimeout(() => { console.log('World!'); }, 2000);
This would log “Hello” to the console, then after two seconds “World!” And in many cases, this is enough: do something, then, after a short delay, do something else. Sorted!
But unfortunately things aren’t always that simple.
You might think that setTimeout
pauses the whole program, but that’s not the case. It’s an asynchronous function, which means the rest of your code won’t wait for it to complete.
For example, say you run this:
console.log('Hello');
setTimeout(() => { console.log('World!'); }, 2000);
console.log('Goodbye!');
You’ll see the following output:
Hello
Goodbye!
World!
Notice how “Goodbye!” appears before “World!”? That’s because setTimeout
doesn’t block the rest of the code from executing.
This means that you can’t do this:
console.log('Hello');
setTimeout(1000);
console.log('World');
“Hello” and “World” will immediately be logged to the console with no noticeable delay occurring in between.
You also can’t do this:
for (let i = 0; i < 5; i++) {
setTimeout(() => { console.log(i); }, 1000);
}
Take a second to consider what might happen in the above code snippet.
It won’t print the numbers 0 to 4 with a delay of one second between each. ather, the numbers 0 to 4 will be logged to the console simultaneously after a delay of one second. Why? Because the loop doesn’t pause execution. It doesn’t wait for setTimeout
to complete before moving on to the next iteration.
To obtain the desired output, we need to adjust the delay in setTimeout
to i * 1000
milliseconds.
for (let i = 0; i < 5; i++) {
setTimeout(() => { console.log(i); }, i * 1000);
}
This staggers the execution of the console.log
statements, ensuring a one-second interval between each output.
The key takeaway here is that setTimeout
doesn’t block a program’s execution, rather the JavaScript interpreter will move on to process the rest of the code and only come back to execute the callback function once the timer expires.
So what is setTimeout
actually good for? Let’s look at that now.
setTimeout() Function Examining and Best Practices
As you can read in our setTimeout
tutorial, the native JavaScript setTimeout
function calls a function or executes a code snippet after a specified delay (in milliseconds).
This might be useful if, for example, you wished to display a popup after a visitor has been browsing your page for a certain amount of time, or you want a short delay before removing a hover effect from an element (in case the user accidentally moused out).
The setTimeout
method accepts a reference to a function as the first argument.
This can be the name of a function:
function greet(){
alert('Howdy!');
}
setTimeout(greet, 2000);
It can be a variable that refers to a function (a function expression):
const greet = function(){
alert('Howdy!');
};
setTimeout(greet, 2000);
Or it can be an anonymous function (in this case an arrow function):
setTimeout(() => { alert('Howdy!'); }, 2000);
It’s also possible to pass setTimeout
a string of code for it to execute:
setTimeout('alert('Howdy!');', 2000);
However, this method is not advisable, as:
- it’s hard to read (and thus hard to maintain and/or debug)
- it uses an implied
eval
, which is a potential security risk - it’s slower than the alternatives, as it has to invoke the JS interpreter
As mentioned, setTimeout
is great for firing a one-off action after a delay, but it’s also possible to use setTimeout
(or its cousin setInterval
) to keep JavaScript waiting until a condition is met. For example, here’s how you might use setTimeout
to wait for a certain element to appear on a web page:
function pollDOM () {
const el = document.querySelector('my-element');
if (el.length) {
// Do something with el
} else {
setTimeout(pollDOM, 300); // try again in 300 milliseconds
}
}
pollDOM();
This assumes the element will turn up at some point. If you’re not sure that’s the case, you’ll need to look at canceling the timer (using clearTimeout
or clearInterval
).
Increasing Timeouts as Alternative to Sleep Function in JavaScript
Sometimes, you might find yourself wanting to introduce delays in a sequence of operations. While you could use various methods to emulate a sleep function, there’s another approach that’s often overlooked: incrementally increasing timeouts.
The idea is simple: instead of pausing the entire execution thread, you increment the delay for each subsequent operation using setTimeout
. This allows you to create a sequence of delayed actions without blocking the browser or compromising the user experience.
Here’s a quick example to illustrate:
let delay = 1000; // Start with a 1-second delay
for (let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(`This is message ${i + 1}`);
}, delay);
delay += 1000; // Increase the delay by 1 second for each iteration
}
In this example, the first message will appear after 1 second, the second after 2 seconds, and so on, up to the fifth message after 5 seconds.
The advantages of this method are that it’s non-blocking, easy to implement, and doesn’t require knowledge of promises or async/await
. However, it isn’t suitable for complex asynchronous operations that require precise timing or error handling.
Flow Control in Modern JavaScript
It’s often the case when writing JavaScript that we need to wait for something to happen (for example, data to be fetched from an API), then do something in response (such as update the UI to display the data).
The example above uses an anonymous callback function for this purpose, but if you need to wait for multiple things to happen, the syntax quickly gets pretty gnarly and you end up in callback hell.
Luckily, the language has evolved considerably over the past few years and now offers us new constructs to avoid this.
For example, using async await we can rewrite the initial code to fetch information from the GitHub API:
(async () => {
const res = await fetch(`https://api.github.com/users/jameshibbard`);
const json = await res.json();
console.log(json.public_repos);
console.log('Hello!');
})();
Now the code executes from top to bottom. The JavaScript interpreter waits for the network request to complete and the number of public repos is logged first, then the “Hello!” message.
If this is more the sort of thing you’re trying to accomplish, I encourage you to read our article Flow Control in Modern JS: Callbacks to Promises to Async/Await.
Bringing Sleep to Native JavaScript
If you’re still with me, then I guess you’re pretty set on blocking that execution thread and making JavaScript wait it out.
Here’s how you might do that:
function sleep(milliseconds) {
const date = Date.now();
let currentDate = null;
do {
currentDate = Date.now();
} while (currentDate - date < milliseconds);
}
console.log('Hello');
sleep(2000);
console.log('World!');
As expected, this will log “Hello”, pause for two seconds, then log “World!”
It works by using the Date.now method to get the number of milliseconds that have elapsed since January 1, 1970 and assigning that value to a date
variable. It then creates an empty currentDate
variable, before entering a do ... while
loop. In the loop it repeatedly gets the number of milliseconds which have elapsed since January 1, 1970 and assigns the value to the previously declared currentDate
variable. The loop will keep going while the difference between date
and currentDate
is less than the desired delay in milliseconds.
Job done, right? Well, not quite …
How to Write Better Sleep Function in JavaScript
Maybe this code does exactly what you’re hoping for, but be aware that it has a large disadvantage: the loop will block JavaScript’s execution thread and ensure that nobody can interact with your program until it finishes. If you need a large delay, there’s a chance that it may even crash things altogether.
So what to do?
Well, it’s also possible to combine the techniques learned earlier in the article to make a less intrusive sleep method:
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
console.log('Hello');
sleep(2000).then(() => { console.log('World!'); });
This code will log “Hello”, wait for two seconds, then log “World!” Under the hood, we’re using the setTimeout
method to resolve a promise after a given number of milliseconds.
Notice that we need to use a then
callback to make sure the second message is logged with a delay. We can also chain more callback functions onto the first:
console.log('Hello');
sleep(2000)
.then(() => { console.log('World!'); })
.then(() => {
sleep(2000)
.then(() => { console.log('Goodbye!'); })
});
This works, but it looks ugly. We can pretty it up using async ... await
:
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function delayedGreeting() {
console.log('Hello');
await sleep(2000);
console.log('World!');
await sleep(2000);
console.log('Goodbye!');
}
delayedGreeting();
This looks nicer, but it means that whatever code is using the sleep
function needs to be marked as async
.
See the Pen
yLLQJrX by SitePoint (@SitePoint)
on CodePen.
Of course, both of these methods still have the disadvantage (or feature) that they don’t pause the entire program execution. Only your function sleeps:
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function delayedGreeting() {
console.log('Hello');
await sleep(2000); // await only pauses the current async function
console.log('World!');
}
delayedGreeting();
console.log('Goodbye!');
The code above logs the following:
Hello
Goodbye!
World!
Best Practices for Creating a JavaScript Sleep Function
We’ve explored various ways to introduce delays in JavaScript. Now let’s recap on which method is best suited for different scenarios, and which one you should generally avoid.
1. Plain setTimeout
console.log('Hello');
setTimeout(() => { console.log('World!'); }, 2000);
- 👍 Pros: Simple to understand, non-blocking.
- 👎 Cons: Offers limited control over asynchronous operations.
- 📝 When to Use: Good for simple, one-off delays, or basic polling.
2. Incremental setTimeout
setTimeout(() => { console.log('Hello'); }, 1000);
setTimeout(() => { console.log('World!'); }, 2000);
- 👍 Pros: Non-blocking, easy to implement, and doesn’t require knowledge of promises or async/await.
- 👎 Cons: Not suitable for complex async operations. No error handling.
- 📝 When to Use: Useful for simple sequences with a delay between each step.
3. Blocking the Event Loop with a Loop
console.log('Hello');
const date = Date.now();
let currentDate = null;
do {
currentDate = Date.now();
} while (currentDate - date < 2000);
console.log('World!');
- 👍 Pros: Mimics traditional sleep behavior.
- 👎 Cons: Blocks the entire thread, can freeze the UI or crash the program.
- ⚠️ Strongly Discouraged: Only use this if you absolutely need to halt execution and are aware of the risks.
4. Using Promises with setTimeout
const sleep = function(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
console.log('Hello');
sleep(2000).then(() => { console.log('World!'); });
- 👍 Pros: Non-blocking, more control over asynchronous operations.
- 👎 Cons: Requires understanding of promises. Longer promise chains can get a bit messy.
- 📝 When to Use: When you need more control over timing and asynchronous operations.
5. Using async/await
with Promises
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function delayedGreeting() {
console.log('Hello');
await sleep(2000);
console.log('World!');
await sleep(2000);
console.log('Goodbye!');
}
delayedGreeting();
- 👍 Pros: Clean syntax, easy to read, non-blocking.
- 👎 Cons: Requires understanding of
async/await
and promises. Requires “wrapping” function outside of modules. - ✅ Strongly Recommended: This is the most modern and clean approach, especially when dealing with multiple asynchronous operations.
Conclusion
Timing issues in JavaScript are the cause of many a developer headache, and how you deal with them depends on what you’re trying to achieve.
Although a sleep function is present in many other languages, I’d encourage you to embrace JavaScript’s asynchronous nature and try not to fight the language. It’s actually quite nice when you get used to it.
If you have any questions, please head over to the SitePoint forums and start a discussion.
FAQs About Sleep, Pause & Wait Functions in JavaScript
Here are some frequently asked questions about creating delays in JavaScript.
Is there a sleep in JavaScript?
No, JavaScript doesn’t have a built-in sleep function, but you can emulate one using setTimeout
or promises with async
/await
.
Is it possible to use the JavaScript sleep function in loops?
Yes, you can use the sleep function in loops if you’re working within an async function or a module:async function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
for (let i = 0; i < 5; i++) { console.log(`Loop count: ${i}`); await sleep(1000); /
* Sleep for 1 second
*/ }
How to sleep for 1 second in JavaScript?
You can use setTimeout
like this:setTimeout(() => { console.log('1 second passed'); }, 1000);
Or use async
/await
with promises:await new Promise(resolve => setTimeout(resolve, 1000)) .then(() => { console.log('1 second passed'); });
How do you sleep 5 seconds in JavaScript?
Similar to sleeping for 1 second, just change the time to 5000 milliseconds:setTimeout(() => { console.log('5 seconds passed'); }, 5000);
Or use async/await with promises:await new Promise(resolve => setTimeout(resolve, 5000)) .then(() => { console.log('5 seconds passed'); });
How to make a timeout in JavaScript?
You can create a timeout using the setTimeout
function:setTimeout(() => { /* Your code here */ }, timeInMilliseconds);
What does wait()
do in JavaScript?
There is no native wait()
function in JavaScript. However, you can create a similar effect using async
/await
with promises or setTimeout
.
Network admin, freelance web developer and editor at SitePoint.