Delay, Sleep, Pause & Wait in JavaScript

James Hibbard
James Hibbard
Share

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

  1. Implementing Delays in Asynchronous JavaScript: This article explores various techniques to implement delays in JavaScript code, emphasizing the language’s asynchronous nature. Unlike many other programming languages that have a built-in sleep function, JavaScript requires alternative methods to introduce delays, which this article aims to explain and demonstrate.
  2. Understanding JavaScript’s Execution Model: A critical aspect of implementing delays in JavaScript is understanding its execution model. JavaScript handles asynchronous operations differently from languages like Ruby, which can lead to unexpected behaviors in timing and sequence of operations. The article highlights this difference with examples, showcasing how JavaScript’s event-driven model impacts the execution of delayed functions.
  3. Best Practices for Creating Delays: The article covers several methods to create delays, such as using setTimeout, promises, and async/await, and discusses the best use cases for each. It also explains common pitfalls, like blocking the event loop, and provides practical solutions and best practices to effectively manage time and asynchronous operations in JavaScript development.
Table of Contents

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.