Skip to main content

Command Palette

Search for a command to run...

JavaScript - Promise, Generator, and Async/Await

Updated
JavaScript - Promise, Generator, and Async/Await

Sync vs. Async

  • Sync: one after another

  • Async: one after another, but not necessarily in order

  • Blog - Sync, Async, Event Loop, and Task Queue

  • The more complicated the web is, the more asynchronous codes are needed

  • However, asynchronous does not guarantee the order of works -> functions or developers cannot predict when the works will start and finish.

  • That was the reason why callback hell happened (to make async functions in order)

  • Therefore, we should express asynchronous operations synchronously

Let Asynchronous Methods Return Values Like Synchronous Methods

Promise, Generator (ES6), async/await (ES7)

  1. Promise + .then

A Promise in JavaScript represents a promise to deliver value at some point in the future after an asynchronous operation has been completed.

  • When a Promise is created using the new operator, the callback passed as an argument is executed immediately.

  • If there is a statement that calls the resolve or reject function inside the callback, the Promise does not move on to the next then or catch block until one of those functions is called.

  • Therefore, the resolve or reject is called only when the asynchronous operation is complete.

new Promise(function (resolve) {
    setTimeout(function () {
        var name = 'Espresso';
        console.log(name);
        resolve(name);
    }, 500);
}).then(function (prevName) {
    return new Promise(function (resolve) {
        setTimeout(function () {
            var name = prevName + ', Americano';
            console.log(name);
            resolve(name);
        }, 500);
    });
}).then(function (prevName) {
    return new Promise(function (resolve) {
        setTimeout(function () {
            var name = prevName + ', Cafe Mocha';
            console.log(name);
            resolve(name);
        }, 500);
    });
}).then(function (prevName) {
    return new Promise(function (resolve) {
        setTimeout(function () {
            var name = prevName + ', Cafe Latte';
            console.log(name);
            resolve(name);
        }, 500);
    });
});
// refactoring
var addCoffee = (name) => {
    return function (prevName) {
        return new Promise(function (resolve) {
            setTimeout(function () {
                var newName = prevName ? `${prevName}, ${name}` : name;
                console.log(newName);
                resolve(newName);
            }, 500);
        });
    };
};

addCoffee('Espresso')()
    .then(addCoffee('Americano'))
    .then(addCoffee('Cafe Mocha'))
    .then(addCoffee('Cafe Latte'));
  1. Generator (ES6)

Functions marked with an asterisk (*) are generator functions in JavaScript. When a generator function is executed, it returns an iterator object (which has a next() method).

  • An iterator is an object that can be iterated through using the next() method. When the next() method is called, the Generator function starts executing from the beginning until it reaches the first yield keyword, where it stops.

  • When next() is called again, the function resumes execution from where it left off until it reaches the next yield keyword and stops again.

  • In other words, if you call the next() method each time an asynchronous operation is completed, the code inside the Generator function will be executed sequentially from top to bottom.

var addCoffee = function (prevName, name) {
    setTimeout(function () {
        coffeeMaker.next(prevName ? prevName + ', ' + name : name);
    }, 500);
};

var coffeeGenerator = function* () {
    var espresso = yield addCoffee('', 'Espresso');
    console.log(espresso);
    var americano = yield addCoffee(espresso, 'Americano');
    console.log(americano);
    var mocha = yield addCoffee(americano, 'Cafe Mocha');
    console.log(mocha);
    var latte = yield addCoffee(mocha, 'Cafe Latte');
    console.log(latte);
};

var coffeeMaker = coffeeGenerator();
coffeeMaker.next();
  1. Promise + Async/Await (ES7)

In ES2017, we can use the new async/await syntax to perform asynchronous operations. To use it, we simply add the async keyword before a function that needs to perform asynchronous operations, and then add the await keyword before any statements that require the result of the asynchronous operation.

var addCoffee = function (name) {
    return new Promise(function (resolve) {
        setTimeout(function(){
            resolve(name);
        }, 500);
    });
};

var coffeeMaker = async function () {
// var coffeeMaker = async () => {
    var coffeeList = '';
    var _addCoffee = async function (name) {
        coffeeList += (coffeeList ? ', ' : '') + await addCoffee(name);
    };
    // wait until _addCoffee() is done
    await _addCoffee('Espresso');
    // execute after _addCoffee('Espresso') is done
    console.log(coffeeList);
    await _addCoffee('Americano');
    console.log(coffeeList);
    await _addCoffee('Cafe Mocha');
    console.log(coffeeList);
    await _addCoffee('Cafe Latte');
    console.log(coffeeList);
};

coffeeMaker();