5 common errors when using Promise

Keywords: Javascript Front-end React Vue

By Ravidu Perera
Translator: front end Xiaozhi
Source: medium

There are dreams and dry goods. Wechat search [Daqian world] pays attention to this bowl washing wisdom who is still washing dishes in the early morning.

This article GitHub https://github.com/qq449245884/xiaozhi It has been included. There are complete test sites, materials and my series of articles for the interview of front-line large factories.

Promise provides an elegant way to handle asynchronous operations in JS. This is also the solution to avoid "callback hell". However, not many developers understand the content. Therefore, many people often make mistakes in practice.

In this article, I will introduce five common errors when using promise. I hope you can avoid these errors.

1. Avoid Promise hell

Usually, Promise is used to avoid callback hell. But abusing them can also lead to Promise being hell.

userLogin('user').then(function(user){
    getArticle(user).then(function(articles){
        showArticle(articles).then(function(){
            //Your code goes here...
        });
    });
});

In the above example, we nested three promise s for userLogin, getararticle and showararticle. In this way, the complexity will increase in proportion to the lines of code, and it may become unreadable.

To avoid this, we need to de nest the code, return getArticle from the first then, and then process it in the second then.

userLogin('user')
  .then(getArticle)
  .then(showArticle)
  .then(function(){
       //Your code goes here...
});

2. Use the try/catch block in Promise

Typically, we use the try/catch block to handle errors. However, try/catch is not recommended in Promise objects.

This is because if there is any error, the Promise object will be processed automatically in the catch.

ew Promise((resolve, reject) => {
  try {
    const data = doThis();
    // do something
    resolve();
  } catch (e) {
    reject(e);
  }
})
  .then(data => console.log(data))
  .catch(error => console.log(error));

In the above example, we used the try/catch block in Promise.

However, Promise itself will catch all errors (even typing errors) within its scope without the need for try/catch blocks. It ensures that all exceptions thrown during execution are obtained and converted into rejected promises.

new Promise((resolve, reject) => {
  const data = doThis();
  // do something
  resolve()
})
  .then(data => console.log(data))
  .catch(error => console.log(error));

**Note: * * it is critical to use the. catch() block in Promise blocks. Otherwise, your test case may fail and the application may crash during the production phase.

3. Use asynchronous functions within Promise blocks

Async / wait is a more advanced syntax for handling multiple promises in synchronous code. When we use the async keyword before a function declaration, it will return a Promise. We can use the await keyword to stop the code until the Promise we are waiting for is resolved or rejected.

However, when you put an Async function in a Promise block, there will be some side effects.

Suppose we want to do an asynchronous operation in Promise block, so we use async keyword, but unfortunately, our code throws an error.

In this way, even if we use the catch() block or wait for your Promise in the try/catch block, we can't deal with this error immediately. Look at the example below.

// This code cannot handle errors
new Promise(async () => {
  throw new Error('message');
}).catch(e => console.log(e.message));

(async () => {
  try {
    await new Promise(async () => {
      throw new Error('message');
    });
  } catch (e) {
    console.log(e.message);
  }
})();

When I encounter async functions within Promise blocks, I try to keep async logic out of Promise blocks to keep it synchronized. Nine out of 10 times can succeed.

However, in some cases, you may need an async function. In this case, there is no choice but to use the try/catch block to manage it manually.

new Promise(async (resolve, reject) => {
  try {
    throw new Error('message');
  } catch (error) {
    reject(error);
  }
}).catch(e => console.log(e.message));


//using async/await
(async () => {
  try {
    await new Promise(async (resolve, reject) => {
      try {
        throw new Error('message');
      } catch (error) {
        reject(error);
      }
    });
  } catch (e) {
    console.log(e.message);
  }
})();

4. Execute Promise block immediately after creating Promise

As for the following code snippet, if we put the code snippet where the HTTP request is called, it will be executed immediately.

const myPromise = new Promise(resolve => {
  // code to make HTTP request
  resolve(result);
});

The reason is that this code is wrapped in a Promise constructor. However, some people may think that it is triggered only after the then method of myPromise is executed.

However, this is not the case. Conversely, when a Promise is created, the callback is executed immediately.

This means that when the following line arrives after establishing myPromise, the HTTP request is likely to be running or at least in the scheduling state.

Promises are always eager to execute the process.

However, if you want to execute Promises later, what should you do? What if you don't want to make an HTTP request now? Is there any magical mechanism built into Promises that enables us to do this?

The answer is to use functions. Functions are a time-consuming mechanism. They only execute when developers explicitly call them with (). Simply defining a function doesn't get us anything. Therefore, the most effective way to make Promise lazy is to wrap it in a function!

const createMyPromise = () => new Promise(resolve => {
  // HTTP request
  resolve(result);
});

For HTTP requests, Promise constructors and callback functions are called only when the function is executed. So now we have a lazy Promise, which will be implemented only when we need it.

5. Promise.all() method is not necessarily used

If you have worked for many years, you should already know what I'm talking about. If there are many promises that are not related to each other, we can deal with them at the same time.

Promise is concurrent, but if you wait for them one by one, it will take too much time. Promise.all() can save a lot of time.

Remember, Promise.all() is our friend

const { promisify } = require('util');
const sleep = promisify(setTimeout);

async function f1() {
  await sleep(1000);
}

async function f2() {
  await sleep(2000);
}

async function f3() {
  await sleep(3000);
}


(async () => {
  console.time('sequential');
  await f1();
  await f2();
  await f3();
  console.timeEnd('sequential');  
})();

The execution time of the above code is about 6 seconds. But if we replace it with Promise.all(), we will reduce the execution time.

(async () => {
    console.time('concurrent');
    await Promise.all([f1(), f2(), f3()]);
    console.timeEnd('concurrent'); 
  })();

summary

In this article, we discussed five common mistakes in using Promise. However, there may be many simple problems that need to be solved carefully.

If you have more related errors, please leave a message and discuss them together.

~After that, I'm the person who wants to go home and set up a stall after retirement. I'll see you next time!

The bugs that may exist after code deployment cannot be known in real time. Afterwards, in order to solve these bugs, we spent a lot of time on log debugging. By the way, we recommend a useful BUG monitoring tool Fundebug.

Original text: https://blog.bitsrc.io/5-common-mistakes-in-using-promises-bfcc4d62657f

communication

The article is continuously updated every week. You can search [Daqian world] on wechat to read it for the first time and reply to [welfare]. There are many front-end videos waiting for you. This article GitHub https://github.com/qq449245884/xiaozhi Already included, welcome Star.

Posted by ravi_aptech on Thu, 25 Nov 2021 18:27:29 -0800