DEV Community

aurel kurtula
aurel kurtula

Posted on

What are Promises in Javascript ?

Javascript is synchronous. Things run one after the other without waiting for previous procedures to change.

let name;
name = 'bob'
console.log(name) // bob
name = 'alice'
console.log(name) // alice
Enter fullscreen mode Exit fullscreen mode

As we would expect, each line above runs one after the other. However, there are many cases where this doesn't help us. For example:

let name;
name = 'bob';
console.log(name); // bob
setTimeout(function(){
  name = 'alice'; 
},100)
console.log(name); // ?
Enter fullscreen mode Exit fullscreen mode

Above we are setting the name to be changed after 100 milliseconds. However, the second log doesn't wait for the change, and so both console logs of name will return "bob". (The name does change but not fast enough.)

solution without a callback

The example we are working with is pretty simple for now, we could easily move the second console log inside the timer and have it done, but let's use a callback function instead.

let name;
const callback = () => console.log(name)
name = 'bob'
console.log(name); // bob
setTimeout(function(){
  name = 'alice';
  callback(); // alice
},100)

Enter fullscreen mode Exit fullscreen mode

Now we are accounting for the delay by adding our console log inside a callback function and letting the setTimeout run the callback in 100 milliseconds.

Promises remove the need for a callback

In plain English, when you make a promise you are saying that you will do something at a given time (when conditions are right). You could say, the timer promises that in 100 milliseconds it will change the name to "alice". Then, when the timer fulfills the promise it's up to us to do something upon the fulfillment. So it's not that different from a callback but it doesn't need to know what happens afterward.

Let's see it in action

let name; 
name = 'bob'
console.log(name); // bob
const ourPromise = new Promise((resolve, reject)=>{ 
  setTimeout(function(){
  name = 'alice';
  resolve();
},100)
})
ourPromise.then(() => console.log(name))
Enter fullscreen mode Exit fullscreen mode

We wrap our setTimeout in a promise and as such the setTimeout doesn't need to know what we will do with the changes it created. The execution of resolve() simply changes the state of the promise from pending to fulfilled, then it's up to use to listen for that change at any point by running the then() method on the promise

Note: if you run console.log(ourPromise) inside the .then() method you'll get an object of { <state>: "fulfilled", <value>: undefined }. If you remove resolve() from the promise and run the console log again inside then(), you'll get { <state>: "pending" }

ourPromise.then(() => console.log(ourPromise))
Enter fullscreen mode Exit fullscreen mode

Scope

As you have seen from the console log when the promise is resolved it usually would deliver some data. In our example, we wanted to test whether the name from our global scope could be changed inside a promise. Pointless in the real world but easy for the sake of demonstration.

Let's see how we could use the internal scope of the promise instead:

let name; 
name = 'bob'
console.log(name); // bob
const ourPromise = new Promise((resolve, reject)=>{ 
  let name; //different to the outside scope
  setTimeout(function(){
    name = 'alice';
    resolve(name); // pass this new name 
  },100)
})
ourPromise.then(resName => console.log(`promised name is ${resName}, and not ${name}`))
console.log(name); // we no longer need this (it still return 'bob'
Enter fullscreen mode Exit fullscreen mode

Inside the promise, we created a new "name" variable (let name) which is completely different from the "name" in the outer scope. Then we change it after 100 milliseconds and this time we pass it with the resolve method.

Note: if we re-try to run the console log inside the then method this time we'll get a value { <state>: "fulfilled", <value>: "alice" }. And in most of the time we would we waiting for a value to come from some api. For example:

fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => response.json())
.then(resolvedData => console.log(resolvedData))
Enter fullscreen mode Exit fullscreen mode

Discussion (0)