When you look at the second hand of a ticking clock, you’ll find out that the second hand moves sequentially. It points at 1 before it does 2, and then 3. It does not point at 4 and then 1 and then 9.

Now imagine that the second hand is the JavaScript runtime and each number is a function. The second hand, which is our imaginary JavaScript runtime, determines what function runs by pointing at the number. When it points at 1, function 1 runs and when it points at 2, function 2 runs. When it points at 3 and function 3 says You’ve asked me to run and I will, but I will not run completely now. Go ahead and ask the statements after me to run. I’ll be done running at a future time and I will notify you when I’m done running, then function 3 is an asynchronous function. When function 3 is done running, it notifies the second hand. When the second hand is done handling all synchronous functions/statements, it goes to function 3 to do whatever should be done after function 3 has run.

Callback functions are usually attached to asynchronous functions so that when the asynchronous function returns with a value, the callback function would accept the value and run with the value. Definitely not the Hussein Bolt type of running, but if you think of it that way, consider “value” to be the baton in a relay race 😉.

Real life examples

It would make more sense help to add practical use cases of asynchronous functions.

setTimeout

setTimeout is an asynchronous function that JavaScript can access. When setTimeout is run with a function f and a number n passed in, it runs completely after n milliseconds after which it releases f to be run by the JavaScript runtime. It does not run completely after it has been asked to run by the JavaScript runtime when it was called. It says to the JavaScript runtime Go ahead and run other statements after me. I’ll notify you after I’m done running. After n milliseconds, it notifies the JavaScript runtime that it is done running and passes f to it so that f will be run when the JavaScript runtime is ready. f runs approximately 1 after n millliseconds.

console.log(1);
console.log(2);
setTimeout(() => {
  console.log("I am function f");
}, 0);
console.log(3);

fetch

According to MDN docs, “the fetch API provides an interface for fetching resources”. In programming, fetching resources (JSON, images, files) across a network is an I/O operation. I/O operations do not have a predictable completion time. They could be held back by anything - poor network, low computer speed, the resource server taking longer to respond, anything. fetch is an asynchronous function. It runs completely at a later time. How does fetch work?

When fetch is called to run by the JavaScript runtime, it immediately returns a promise. See “promise” as an empty gift box with two partitions. fetch says to the runtime I’ve been called to run, and I will. Go ahead and run other statements after me, but hold this empty gift box for now. When I’m done running, whatever value I get, I’ll place it in the box and notify you. If I run completely without any error, I’ll pass the value I return with into partition one. If there are any errors, I’ll pass the error into partition two. For a five-letter function name, I think that’s a lot of talking.

Partition one is the function called then and you guessed right, catch is partition two. We pass functions into then and catch so that whenever fetch returns with a value, the functions we passed into then or catch will run with the value passed into them.

Is JavaScript an Asynchronous Programming Language?

No. JavaScript is not an asynchronous programming language. So what are setTimeout and fetch?. Well, technically, these functions are not JavaScript functions. Both are attached to the window and global objects in the browser and Node.js. These functions are abstractions.

Think of a door handle. As a user of the door handle, you do not have to know what happens inside the door handle that makes it open the door when you pull it. All you have to do is pull the handle a certain way and the door is opened. You, the puller of the door handle, are different from the door handle. You do not own the mechanism for opening the door. You only use it through the handle. JavaScript too is like you, and these functions are like the door handle. All JavaScript has to do is call these functions and the real deal starts to work in the programming language that the window or the global object was written in.

To make it clearer, here’s another example: addEventListener. addEventListener is not a JavaScript function or method. It is attached to the DOM. If addEventListener were a JavaScript method, it will exist everywhere that JavaScript exists, including Node.js; but it doesn’t exist in Node.js.

Conclusion

There you have it. An asynchronous function is one that completely runs at a later time and will not prevent the statements that are to run after it from running. It will notify the JavaScript runtime after it is done running for the JavaScript runtime to take action. This behaviour is different from a long-running Fibonacci function which is synchronous and will prevent the functions after it from running until it runs completely.

People illustrations by Storyset


  1. approximately because the JavaScript runtime will run all synchronous functions to completion before running f, even after n milliseconds has elapsed. ↩︎