DEV Community

Trung Hieu Nguyen
Trung Hieu Nguyen

Posted on

Some mistakes with async and promise in Javascript

Hi, today I'm gonna talk about Javascript Promises, Async-await, and some mistakes which I made when working with them.

I will come back to update this post whenever I find out any new mistake.

1. Never fully trust your console.*(..)

Hmm, it might be not really related to our topic today, but actually, it is. This might rarely happen (actually for the past 2 years, I've just encountered it several times).

console.* is not standardized and there is no specification or rules which show how console.* methods works. So we can't know for sure the behavior of console.*. Their results can be changed from time to time, the result of the example I'm going to show might not be the same as the result you see on your browser at the time you read this blog. We never know.

Let's see a very simple example:

const a = {
    value: 10,
};
console.log(`a`, a);
a.value = 20;
Enter fullscreen mode Exit fullscreen mode

What you guys might expect to see is:

{value: 10}
Enter fullscreen mode Exit fullscreen mode

and it actually is, but I want to point out that, SOMETIME, it will log like this:

{value: 20}
Enter fullscreen mode Exit fullscreen mode

It's hard for me to reproduce a case to show you guys but it really can happen, maybe when you run a very large project and rapidly make changes to code then the console.* will have some strange behavior that you never know.

If you run into the above scenario, the best option you can do is that use a debugger instead or stick with JSON.stringify to take a "snapshot" of your variable (I'm talking about object type)

2. Resolve/Reject is not equivalent to "return"

One mistake that I made during development is that I assumed resolve/reject is the "return" keyword of a Promise. Technically, it's true, but one thing to notice is that even if you called resolve/reject, your Promise will not stop at that point but will exec till the end of the Promise.

Let's see this example:

const a = new Promise((resolve) => {
    resolve(1);
    console.log("still go here");
});

a.then((res) => {
    console.log(res);
});

// Result
still go here
1
Enter fullscreen mode Exit fullscreen mode

And

const a = new Promise((resolve, reject) => {
    reject(2);
    console.log("still go here");
});

a.then((res) => {
    console.log(res);
}).catch((err) => {
    console.log(err);
});
// Result
still go here
2
Enter fullscreen mode Exit fullscreen mode

Even though you called resolve/reject before the console.log, it's still printed out on screen which means Promise still go to that line and execute code after resolve/reject has been called.

It's not the same as functions which if you call "return', the function will stop at that point (I'm not talking about conditional return).

I want to share this with you guys because in the past, because of assuming resolve/reject as "return", I made a bug that took me 2 days to fix!

3. The first will be chosen

In your promise, you can call resolve/reject multiple times, but only the first one will be accepted and be the output of your Promise. Of course, I'm talking about the normal flow, if it's conditional flow, it will be a different story.

const a = new Promise((resolve) => {
    resolve(1);
    resolve(2);
});

a.then(console.log);

// Output: 
1
Enter fullscreen mode Exit fullscreen mode
const a = new Promise((resolve, reject) => {
    reject(2);
    reject(1);
});

a.catch(console.log);
**// Output
2**
Enter fullscreen mode Exit fullscreen mode

The same thing happens with the parameters you pass to resolve/reject, you can call resolve/reject with multiple parameters, but only the first one will be chosen to be the value of resolve/reject, all subsequent parameters beyond the first one will be silent ignore.

const a = new Promise((resolve, reject) => {
    resolve(1, 2, 3);
});

a.then(console.log);

// Ouput
1
Enter fullscreen mode Exit fullscreen mode

If you want to return more than 1 value, you have no choice but put them into object or array.

const a = new Promise((resolve, reject) => {
    resolve([1, 2, 3]);
});

a.then(console.log);

// Ouput
[1,2,3]
Enter fullscreen mode Exit fullscreen mode

4. Unnecessary await return.

Okay, let me make it more clear.

Consider below example

const promise = () =>
    new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("done");
        }, 1500);
    });

const makeRequest = async () => {
    return await promise();
};

const test = async () => {
    const result = await makeRequest();
    console.log(result);
};

test();

// result
// after 1.5s, print out "done"
Enter fullscreen mode Exit fullscreen mode

Notice about the return await promise() . I think not only me but many other beginners sometimes write such code like that. It's not wrong, but to me, it's kind of useless. Since make request might make some asynchronous request to the server and return another promise. if we don't have to process anything with the data but return it immediately, we don't have to await the response before return

This code also works the same as the above:

const promise = () =>
    new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("done");
        }, 1500);
    });

const makeRequest = async () => {
    return promise();
};

const test = async () => {
    const result = await makeRequest();
    console.log(result);
};

test();

// Result
// after 1.5s, print out "done"
Enter fullscreen mode Exit fullscreen mode

Okay, that's it for today. See you guys next time. Bye bye

Top comments (0)