2

Synchronous vs Asynchronous Callbacks

 2 years ago
source link: https://dev.to/maximization/synchronous-vs-asynchronous-callbacks-3li
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Cover image for Synchronous vs Asynchronous Callbacks
Maxim Orlov

Posted on Nov 16

• Originally published at maximorlov.com

Synchronous vs Asynchronous Callbacks

This article was originally published at https://maximorlov.com/synchronous-vs-asynchronous-callbacks/

Asynchronous code in JavaScript can be confusing at best, and at worst, preventing you from landing your first job or implementing an urgent feature at work.

Just when you started to build a mental model of your program, asynchronous code jumps right in and messes it all up leaving you in utter disillusion.

To understand how asynchronous code works, it's important to know the difference between synchronous and asynchronous callbacks and recognise them in your code.

Before we dive in, let's first do a refresher on callback functions. If you already know what callback functions are, feel free to skip to the next section.

What is a callback function?

A callback function is a function passed as an argument to another function in order to be called from inside that function. This may sound confusing, so let's look at some code:

function printToConsole(greeting) {
  console.log(greeting);
}

function getGreeting(name, cb) {
   cb(`Hello ${name}!`);
}

getGreeting('Maxim', printToConsole); // Hello Maxim!
Enter fullscreen modeExit fullscreen mode

In the above example, the function printToConsole is passed as an argument to getGreeting. Inside getGreeting, we call printToConsole with a string which is then printed to the console. Because we pass printToConsole to a function to be called from inside that function, we can say that printToConsole is a callback function.

In practice, callback functions are often initialised anonymously and inlined in the function call. The following example is equivalent to the one above:

function getGreeting(name, cb) {
  cb(`Hello ${name}!`);
}

getGreeting('Maxim', (greeting) => {
  console.log(greeting);
}); // Hello Maxim!
Enter fullscreen modeExit fullscreen mode

The difference is that printToConsole is now an anonymous callback function. Nonetheless, it's still a callback function!

Here's another example you may be familiar with:

function multiplyByTwo(num) {
    return num * 2;
}

const result = [1, 2, 3, 4].map(multiplyByTwo);
console.log(result); // [2, 4, 6, 8]
Enter fullscreen modeExit fullscreen mode

Here, multiplyByTwo is a callback function because we pass it as an argument to .map(), which then runs the function with each item in the array.

Similar to the previous example, we can write multiplyByTwo inline as an anonymous callback function:

const result = [1, 2, 3, 4].map((num) => {
    return num * 2;
});
console.log(result); // [2, 4, 6, 8]
Enter fullscreen modeExit fullscreen mode

Order of execution

All the callbacks we've seen so far are synchronous. Before we discuss asynchronous callbacks, let's have a look at the program's order of execution first.

In what order do you think the following console.log statements are printed?

console.log('start');

function getGreeting(name, cb) {
  cb(`Hello ${name}!`);
}

console.log('before getGreeting');

getGreeting('Maxim', (greeting) => {
  console.log(greeting);
});

console.log('end');
Enter fullscreen modeExit fullscreen mode

If your answer was:

start
before getGreeting
Hello Maxim!
end
Enter fullscreen modeExit fullscreen mode

You got it right! The program starts at the top and executes each line sequentially as it goes to the bottom. We do a mental jump up and down when we call getGreeting to go to the function's definition and then back to execute the callback function, but otherwise, nothing weird is happening.

Asynchronous Callbacks

Now let's have a look at asynchronous callbacks by converting getGreeting to run asynchronously:

console.log('start');

function getGreetingAsync(name, cb) {
   setTimeout(() => {
     cb(`Hello ${name}!`);
   }, 0);
}

console.log('before getGreetingAsync');

getGreetingAsync('Maxim', (greeting) => {
  console.log(greeting);
});

console.log('end');
Enter fullscreen modeExit fullscreen mode

In what order do you think the console.log statements are printed this time around?

Go ahead, I'll wait.
.
.
.
.
.
.
.
.
.
.

The right answer is:

start
before getGreetingAsync
end
Hello Maxim!
Enter fullscreen modeExit fullscreen mode

With the addition of setTimeout, we're deferring execution of the callback function to a later point in time. The callback function will run only after the program has finished executing the code from top to bottom (even if the delay is 0ms).

The main difference between synchronous and asynchronous callbacks is that synchronous callbacks are executed immediately, whereas the execution of asynchronous callbacks is deferred to a later point in time.

This may be confusing at first, especially if you're coming from synchronous languages like PHP, Ruby or Java. To understand what's going on in the background, you'll have to learn how the event loop works.

How can you tell if a callback is synchronous or asynchronous?

Whether a callback is executed synchronously or asynchronously depends on the function which calls it. If the function is asynchronous, then the callback is asynchronous too.

Asynchronous functions are usually the ones that do a network request, wait for an I/O operation (like a mouse click), interact with the filesystem or send a query to a database. What these functions have in common is that they interact with something outside the current program and your application is left waiting until a response comes back.

Conversely, synchronous callbacks are executed within the program's current context and there's no interaction with the outside world. You'll find synchronous callbacks in functional programming where, for example, the callback is called for each item in a collection (eg. .filter(), .map(), .reduce() etc.). Most prototype methods in the JavaScript language are synchronous.

If you're not sure whether a callback function is executed synchronously or asynchronously, you can add console.log statements inside and after the callback and see which one is printed first.

Learn how to write asynchronous code in Node.js

Write clean and easy to read asynchronous code in Node.js with this FREE 5-day email course.

Visual explanations will teach you how to decompose asynchronous code into individual parts and put them back together using a modern async/await approach. Moreover, with 30+ real-world exercises you'll transform knowledge into a practical skill that will make you a better developer.

Refactoring Callbacks, a FREE 5-day email course. 30+ real-world exercises, a visual guide and 5 days, 5 lessons.

👉 Get Lesson 1 now


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK