My Brain

Asynchronous Code and Callback Functions

  • Synchronous code always runs before asynchronous code.

For example the console log runs before the setTimeout function (which is async)

setTimeout(() => [
  console.log('Inside timeout')
])

console.log('hello')

// hello
// Inside timeout

Promises

  • Promises is another way to represent asynchronous code
  • A promise is an object with 3 states: pending, resolved and rejected.

The following promise:

const myPromise = new Promise((resolve, reject) => {
  resolve("hello")
})

console.log(myPromise);
// Promise { 'hello' }

As we can see, we get a pending object.

In order to get the actual value we need to resolve it.

const myPromise = new Promise((resolve, reject) => {
  resolve("hello")
})

myPromise.then((val) => {
  console.log(val);
})

// hello

Instead of getting an object with pending state, we get the resolved promise.

We can chain .then infinitely:

const myPromise = new Promise((resolve, reject) => {
  resolve("hello")
})

myPromise.then((val) => {
  console.log(val);

  return 10;
}).then((newVal) => {
  console.log(newVal)
})

// 10

If we reject the promise, we can catch the error thrown:

const myPromise = new Promise((resolve, reject) => {
  reject("error!")
})

myPromise.then((val) => {
  console.log(val);
}).catch((err) => {
  console.log(err);
})

// error!

A better example with setTimeout():

const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Hello after 1 second")
  }, 1000)
})

myPromise.then((val) => {
  console.log(val);
}).catch((err) => {
  console.log(err);
})

// Hello after 1 second <== after 1 second

But we can have the promise inside a function:

const myPromiseFunc = (num) => {
  return new Promise((resolve, reject) => {
    if (num > 5) {
      resolve('number is > 5')
    } else {
      reject('number is < 5')
    }
  })
}

myPromise(10).then((val) => {
  console.log(val);
}).catch((err) => {
  console.log(err);
})

// number if > 5

If we trigger the reject instead:

const myPromiseFunc = (num) => {
  return new Promise((resolve, reject) => {
    if (num > 5) {
      resolve('number is > 5')
    } else {
      reject('number is < 5')
    }
  })
}

myPromise(3).then((val) => {
  console.log(val);
}).catch((err) => {
  console.log(err);
})

// ERROR: number if < 5

Using Async/Await

const myPromiseFunc = (num) => {
  return new Promise((resolve, reject) => {
    if (num > 5) {
      resolve('number is > 5')
    } else {
      reject('number is < 5')
    }
  })
}

async function executeMyPromise() {
  try {
    const val = await myPromiseFunc(10)
    console.log(val)
  } catch (error) {
    console.log('ERROR:', error)
  }
}

Dealing with multiple promises

const myPromiseFunc = (num) => {
  return new Promise((resolve, reject) => {
    if (num > 5) {
      resolve('number is > 5')
    } else {
      reject('number is < 5')
    }
  })
}

async function executeMyPromise() {
  try {
    const val = await fetch1()
    const otherVal = await fetch2(val) // here the second depends on the value from the first promise
    console.log(val)
  } catch (error) {
    console.log('ERROR:', error)
  }
}

But if they can be handled in parallel (they are independent from each other):

const myPromiseFunc = (num) => {
  return new Promise((resolve, reject) => {
    if (num > 5) {
      resolve('number is > 5')
    } else {
      reject('number is < 5')
    }
  })
}

async function executeMyPromise() {
  try {
    const promises = [fetch1(), fetch2()]

    const result = await Promise.all(promises);
    // result will be an array of resolved values. If one promise fails, all fail.
    // Or as well:
    const [ val1, val2 ] = await Promise.all(promises);
  } catch (error) {
    console.log('ERROR:', error)
  }
}

Backlinks