Getting Sleep() with Promises in JS
By: Noam Sauer-Utley
Tags: Promises, Flatiron School, Programming, Asynchronous, JavaScript

Getting Sleep() with Promises in JS

Recently, I started building a very basic single page app to illustrate Fetch API usage in a cute and simple way.

When the user clicks a button styled like a tennis ball, a new dog image is fetched from the Dog API, and given a name fetched from the Namey API.

The dog’s image is loaded onto the page, and with each fetch, a name is added onto a list of fetched dogs.

However, once a few dogs were fetched, the document content stretched down quite far, and required a bit of scrolling to view. I decided to add a handy little link in the page footer which would scroll the viewer right up to the top, and re-fire the fetch cycle.

Javascript makes this easy:

We can just scroll up the window, then trigger a new click event on the button we’ve assigned to the variable button.

However, the the combo of the page scrolling up and the image fetch simultaneously re-firing looks pretty messy.

Yikes.

I wanted a way to slow things down, so the user would only see one thing happening on the page at a time.

I knew that if I could just pause for half a second between the scroll and the API Fetch, everything would look much smoother.

Suddenly, I missed Ruby’s sleep method. It was so nice to be able to schedule events to the exact time I wanted them to run!

I decided there had to be a way to construct my own dupe of that handy little method.

If you’re not familiar with JS Promises, it’s important to first understand that while Javascript is single-threaded (meaning it can only process one statement at a time), it is also asynchronous (meaning it can start processing a new statement before the previous statement has resolved, allowing it to multitask time-consuming processes in the background.).

Javascript uses Promises to track the resolution of those background processes, allowing us to set certain statements to run only when a time-consuming process has resolved and returned its completed result.

This is great for handling fetch requests and other time consuming processes, but it also gives us a way to tell our app to wait to process certain statements until exactly when we want them to be run.

I realized that I could exploit this functionality by building a Promise around Javascript’s built-in setTimeout() method.

Let’s make a promise:

setTimeout() takes in two parameters:

1: A function to be executed after the timer expires. 2: The time, in milliseconds (thousandths of a second), the timer should wait before the specified function or code is executed. If this argument is omitted, a value of 0 is used, meaning execute “immediately”, or more accurately, as soon as possible. Note that in either case, the actual delay may be longer than intended

We can create a new Promise, and tell setTimeout to pass the Promise resolve statement as setTimeout’s first parameter. setTimeout will delay for ms milliseconds, then resolve the promise. If we throw this in a function, we now have a handle little delay function ready to go!

Great! Now we made our replacement for Ruby’s sleep method.

Now let’s put it to use.

I decided to take advantage of one of ES6’s fresher bits of syntax for Promise handling: Async/await.

delayedClick() knows from the get that it’s awaiting a promise resolution. We’re using our brand new sleep() function as the awaited promise, passing in our desired number of milliseconds (in this case, 700ms, or 7/10ths of a second). Once that promise resolves, we can enter the action we want delayedClick() to enact. In this case, we’re going to click the button that re-starts the fetch and display cycle.

Now that we have our delay and desired action plugged into a method, we can plug delayedClick() into our existing scrollAndThrow() method as a replacement to button.click() to slow things down and clean up the onscreen process.

The result: no more jaggedy mid-scroll fetch return and image load!

Much nicer!

Sometimes, it’s just good to get some sleep!