Skip to main content

Asynchronous code pitfalls

Using Promises incorrectly

Not respecting the order of code execution can have unexpected results. For instance:

async function determineCultureLevel() {
    let cultureLevel = "Philistine";
    let promise = new Promise((resolve, reject) => {
        // Do some operation that takes 500ms, that determines the user is a cultured user
        setTimeout(() => {
            resolve("Cultured");
        }, 500);
    });
    promise.then((value) => {
        cultureLevel = value;
    });
    console.log("Your culture level is: " + cultureLevel);
}

Here, we are using a promise to do some asynchronous work outside the main thread. However, if we run this code, we get the following result:

image.png

The problem is that when we call console.log to print the result, the promise has not resolved yet; the code that resolves it has not finished executing. As a result, the promise's then() function has not yet been called, so the cultureLevel variable has not been updated. There are two ways we can solve this:

Await the results of the promise

If we need the result of the promise before we proceed, we can wait until it has resolved using the await keyword.

async function determineCultureLevel() {
    let cultureLevel = "Philistine";
    cultureLevel = await new Promise((resolve, reject) => {
        // Do some operation that takes 500ms, that determines the user is a cultured user
        setTimeout(() => {
            resolve("Cultured");
        }, 500);
    });
    console.log("Your culture level is: " + cultureLevel);
}

We don't need a then() function here; the await keyword implicitly returns the resolved value of the promise, not the promise object itself. As such we can directly assign it to cultureLevel to get the correct result.

image.png

Chained then() calls

The other solution involves chaining then() calls. In this simple scenario, we only need one then() function, but in more complex operations where we need to wait for multiple different functions to finish in sequence, multiple then() functions are needed.

Suppose we had three variables to calculate, but we needed to do each one in sequence. We could do it like this:

async function determineCultureLevel() {
    let cultureLevel = "Philistine", homm3 = "Bad Game", coffee = "Unnecessary";
    let promise = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("Cultured");
        }, 500);
    }).then((value) => {
        cultureLevel = value;
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve("good game");
            }, 500);
        });
    }).then((value) => {
        homm3 = value;
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve("a life force");
            }, 500);
        });
    }).then((value) => {
        coffee = value;
        console.log("Your culture level is: " + cultureLevel);
        console.log("HOMM3 is a: " + homm3);
        console.log("Coffee is: " + coffee);
    });
}

determineCultureLevel();

The same code is below, a little more compact so it'll fit neatly into one screenshot, showing the result.

image.png