Promises VS Callbacks

Promises and callbacks are both ways to handle asynchronous code in JavaScript. A callback is a function passed as an argument to another function and executed after the first function has been completed. A Promise is an object that is returned immediately, representing a value that may not be available yet. Promises are more powerful than callbacks because they provide a way to compose asynchronous operations and methods to handle errors. Promises also provide better readability and maintainability by eliminating the need for nested code blocks.

Promises

Promises are object that are returned as soon as you call them allow the thread to continue processing and will return once the process inside the promise is complete. Here is a simple example:

 1function oneSecond(msg) {
 2  return new Promise((resolve) => {
 3    setTimeout(() => {
 4      resolve(msg);
 5    }, 1000);
 6  });
 7}
 8
 9oneSecond("Hello World").then((msg) => {
10  console.log(msg);
11});
12console.log("Promise called!");

The expected output of this should look like this:

1> "Promise called!"
2> "Hello Word"

As you can see the main process has continued to run letting the code in the promise complete in its own time.

Callbacks

Callbacks work similarly to promises, below is the same example written with a callback instead.

 1function oneSecond(msg, callback) {
 2  setTimeout(() => {
 3    callback(msg);
 4  }, 1000);
 5}
 6
 7oneSecond("Hello World", (msg) => {
 8  console.log(msg);
 9});
10console.log("Callback called!");

Differences

Promises are returned by the main function while callbacks are not called until the code inside has been completed. Promises also have a couple of other features like the ability to run asynchronously and synchronously using the await keyword. Below is an example using the same oneSecond() function above.

1let msg = await oneSecond("Hello World");
2console.log(msg);
3console.log("Promise called");

The output would look like this because the thread waits for the promise to fulfill itself before continuing.

1> "Hellow World"
2> "Promise called"

Another feature of promises is the ability to reject the promise if an error occurs.

 1function oneSecond(msg) {
 2  return new Promise((resolve, reject) => {
 3    if (msg.length < 5) {
 4      setTimeout(() => {
 5        resolve(msg);
 6      }, 1000);
 7    } else {
 8      reject("Message too long");
 9    }
10  });
11}
12
13oneSecond("Hello World")
14  .then((msg) => {
15    console.log(msg);
16  })
17  .catch((err) => {
18    console.log(err);
19  });
20console.log("Promise called!");

The output would look like this.

1> "Message too long"
2> "Promise called"

The error message shows first because the if statement doesn't ever call the setTimeout function because the message is greater than 5 characters. When the reject function is called, the output skips all of the then statements and just to the catch statement that handles all rejections.