Home > Web Front-end > JS Tutorial > Quickly learn Promise and Async/Await in JavaScript

Quickly learn Promise and Async/Await in JavaScript

青灯夜游
Release: 2021-01-30 10:01:05
forward
1471 people have browsed it

Quickly learn Promise and Async/Await in JavaScript

Generally in development, querying network API operations is often time-consuming, which means it may take a while to wait to get a response. Therefore, in order to avoid the situation where the program becomes unresponsive when requested, asynchronous programming has become a basic skill for developers.

When dealing with asynchronous operations in JavaScript, we usually hear the concept of "Promise". But understanding how it works and how to use it can be abstract and difficult to understand.

Related recommendations: "javascript video tutorial"

So, in this article we will use practical methods to help you understand their concepts and usage more quickly , so unlike many traditional dry tutorials, we will start with the following four examples:

  • Example 1: Explaining the basics of Promise with birthdays
  • Example 2: A Number guessing game
  • Example 3: Get country information from Web API
  • Example 4: Get a list of neighboring countries of a country from Web API

Example 1: Using birthdays to explain the basics of Promise

First, let’s take a look at the basic form of Promise.

There are three states when Promise is executed: pending (executing), fulfilled (successful), and rejected (failed).

new Promise(function(resolve, reject) {
    if (/* 异步操作成功 */) {
        resolve(value); //将Promise的状态由padding改为fulfilled
    } else {
        reject(error); //将Promise的状态由padding改为rejected
    }
})
实现时有三个原型方法then、catch、finally
promise
.then((result) => {
    //promise被接收或拒绝继续执行的情况
})
.catch((error) => {
    //promise被拒绝的情况
})
.finally (() => {
    //promise完成时,无论如何都会执行的情况
})
Copy after login

The basic form introduction is complete, so let’s start looking at the following examples.

User Story: My friend Kayo promised to make me a cake for my birthday party in two weeks.

If everything goes well and Kayo doesn't get sick, we will get a certain amount of cake, but if Kayo gets sick, we will have no cake. But with or without cake, we will still have a birthday party.

So for this example, we translate the above background story into JS code. First, let us create a function that returns a Promise.

const onMyBirthday = (isKayoSick) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (!isKayoSick) {
        resolve(2);
      } else {
        reject(new Error("I am sad"));
      }
    }, 2000);
  });
};
Copy after login

In JavaScript, we can use new Promise() to create a new Promise, which accepts a function with the parameters: (resolve, reject)=>{}.

In this function, resolve and reject are the callback functions provided by default. Let's take a closer look at the above code.

When we run the onMyBirthday function 2000ms later.

  • If Kayo is not sick, then we execute the resolve function with 2 as the parameter
  • If Kayo is sick, then we execute it with new Error("I am sad") as the parameter reject. Although you can pass anything you want to reject as a parameter, it is recommended to pass it an Error object.

Now, because onMyBirthday() returns a Promise, we have access to the then, catch, and finally methods. We can also access the parameters passed to resolve and reject earlier in then and catch using the parameters passed to resolve and reject.

Let us understand the concept through the following code

If Kayo is not sick

onMyBirthday(false)
  .then((result) => {
    console.log(`I have ${result} cakes`); // 控制台打印“I have 2 cakes” 
  })
  .catch((error) => {
    console.log(error); // 不执行
  })
  .finally(() => {
    console.log("Party"); // 控制台打印“Party”
  });
Copy after login

If Kayo is sick

onMyBirthday(true)
  .then((result) => {
    console.log(`I have ${result} cakes`); // 不执行 
  })
  .catch((error) => {
    console.log(error); // 控制台打印“我很难过”
  })
  .finally(() => {
    console.log("Party"); // 控制台打印“Party”
  });
Copy after login

I believe you can understand Promise through this example basic concept.

Let’s start with Example 2

Example 2: A guessing game

Basic requirements:

  • User You can enter any number
  • The system randomly generates a number from 1 to 6
  • If the number entered by the user is equal to the system's random number, the user will be given 2 points
  • If the user enters a number The difference from the system random number is 1, and the user will be given 1 point. Otherwise, the user will be given 0 points.
  • The user can play as long as he wants

For the above requirements, we first create an enterNumber function and returns a Promise:

const enterNumber = () => {
  return new Promise((resolve, reject) => {
    // 从这开始编码
  });
};
Copy after login

The first thing we do is ask the user for a number and randomly select a number between 1 and 6:

const enterNumber = () => {
  return new Promise((resolve, reject) => {
    const userNumber = Number(window.prompt("Enter a number (1 - 6):")); // 向用户索要一个数字
    const randomNumber = Math.floor(Math.random() * 6 + 1); // 选择一个从1到6的随机数
  });
};
Copy after login

When the user enters A value that is not a number. In this case, we call the reject function and throw the error:

const enterNumber = () => {
  return new Promise((resolve, reject) => {
    const userNumber = Number(window.prompt("Enter a number (1 - 6):")); // 向用户索要一个数字
    const randomNumber = Math.floor(Math.random() * 6 + 1); //选择一个从1到6的随机数

    if (isNaN(userNumber)) {
      reject(new Error("Wrong Input Type")); // 当用户输入的值非数字,抛出异常并调用reject函数
    }
  });
};
Copy after login

Below, we need to check if userNumber is equal to RanomNumber, if equal, we give the user 2 points, and then we can execute the resolve function to pass a object { points: 2, randomNumber } object.

If the difference between userNumber and randomNumber is 1, then we give the user 1 point. Otherwise, we give the user 0 points.

return new Promise((resolve, reject) => {
  const userNumber = Number(window.prompt("Enter a number (1 - 6):")); // 向用户索要一个数字
  const randomNumber = Math.floor(Math.random() * 6 + 1); // 选择一个从1到6的随机数

  if (isNaN(userNumber)) {
    reject(new Error("Wrong Input Type")); // 当用户输入的值非数字,抛出异常并调用reject函数
  }

  if (userNumber === randomNumber) {
    // 如果相等,我们给用户2分
    resolve({
      points: 2,
      randomNumber,
    });
  } else if (
    userNumber === randomNumber - 1 ||
    userNumber === randomNumber + 1
  ) {
    // 如果userNumber与randomNumber相差1,那么我们给用户1分
    resolve({
      points: 1,
      randomNumber,
    });
  } else {
    // 否则用户得0分
    resolve({
      points: 0,
      randomNumber,
    });
  }
});
Copy after login

Next, let us create another function to ask the user if he wants to continue the game:

const continueGame = () => {
  return new Promise((resolve) => {
    if (window.confirm("Do you want to continue?")) { // 向用户询问是否要继续游戏
      resolve(true);
    } else {
      resolve(false);
    }
  });
};
Copy after login

In order not to force the game to end, the Promise we created does not use the Reject callback.

Below, we create a function to handle the guessing logic:

const handleGuess = () => {
  enterNumber() // 返回一个Promise对象
    .then((result) => {
      alert(`Dice: ${result.randomNumber}: you got ${result.points} points`); // 当resolve运行时,我们得到用户得分和随机数 
      
      // 向用户询问是否要继续游戏
      continueGame().then((result) => {
        if (result) {
          handleGuess(); // If yes, 游戏继续
        } else {
          alert("Game ends"); // If no, 弹出游戏结束框
        }
      });
    })
    .catch((error) => alert(error));
};

handleGuess(); // 执行handleGuess 函数
Copy after login

在这当我们调用handleGuess函数时,enterNumber()返回一个Promise对象。

如果Promise状态为resolved,我们就调用then方法,向用户告知竞猜结果与得分,并向用户询问是否要继续游戏。

如果Promise状态为rejected,我们将显示一条用户输入错误的信息。

不过,这样的代码虽然能解决问题,但读起来还是有点困难。让我们后面将使用async/await 对hanldeGuess进行重构。

网上对于 async/await 的解释已经很多了,在这我想用一个简单概括的说法来解释:async/await就是可以把复杂难懂的异步代码变成类同步语法的语法糖

下面开始看重构后代码吧:

const handleGuess = async () => {
  try {
    const result = await enterNumber(); // 代替then方法,我们只需将await放在promise前,就可以直接获得结果

    alert(`Dice: ${result.randomNumber}: you got ${result.points} points`);

    const isContinuing = await continueGame();

    if (isContinuing) {
      handleGuess();
    } else {
      alert("Game ends");
    }
  } catch (error) { // catch 方法可以由try, catch函数来替代
    alert(error);
  }
};
Copy after login

通过在函数前使用async关键字,我们创建了一个异步函数,在函数内的使用方法较之前有如下不同:

  • 和then函数不同,我们只需将await关键字放在Promise前,就可以直接获得结果。
  • 我们可以使用try, catch语法来代替promise中的catch方法。

下面是我们重构后的完整代码,供参考:  

const enterNumber = () => {
  return new Promise((resolve, reject) => {
    const userNumber = Number(window.prompt("Enter a number (1 - 6):")); // 向用户索要一个数字
    const randomNumber = Math.floor(Math.random() * 6 + 1); // 系统随机选取一个1-6的数字

    if (isNaN(userNumber)) {
      reject(new Error("Wrong Input Type")); // 如果用户输入非数字抛出错误
    }

    if (userNumber === randomNumber) { // 如果用户猜数字正确,给用户2分
      resolve({
        points: 2,
        randomNumber,
      });
    } else if (
      userNumber === randomNumber - 1 ||
      userNumber === randomNumber + 1
    ) { // 如果userNumber与randomNumber相差1,那么我们给用户1分
      resolve({
        points: 1,
        randomNumber,
      });
    } else { // 不正确,得0分
      resolve({
        points: 0,
        randomNumber,
      });
    }
  });
};

const continueGame = () => {
  return new Promise((resolve) => {
    if (window.confirm("Do you want to continue?")) { // 向用户询问是否要继续游戏
      resolve(true);
    } else {
      resolve(false);
    }
  });
};

const handleGuess = async () => {
  try {
    const result = await enterNumber(); // await替代了then函数

    alert(`Dice: ${result.randomNumber}: you got ${result.points} points`);

    const isContinuing = await continueGame();

    if (isContinuing) {
      handleGuess();
    } else {
      alert("Game ends");
    }
  } catch (error) { // catch 方法可以由try, catch函数来替代
    alert(error);
  }
};

handleGuess(); // 执行handleGuess 函数
Copy after login

我们已经完成了第二个示例,接下来让我们开始看看第三个示例。

示例3:从Web API中获取国家信息

一般当从API中获取数据时,开发人员会精彩使用Promises。如果在新窗口打开https://restcountries.eu/rest/v2/alpha/cn,你会看到JSON格式的国家数据。

通过使用Fetch API,我们可以很轻松的获得数据,以下是代码:

const fetchData = async () => {
  const res = await fetch("https://restcountries.eu/rest/v2/alpha/cn"); // fetch() returns a promise, so we need to wait for it

  const country = await res.json(); // res is now only an HTTP response, so we need to call res.json()

  console.log(country); // China's data will be logged to the dev console
};

fetchData();
Copy after login

现在我们获得了所需的国家/地区数据,让我们转到最后一项任务。

示例4:从Web API中获取一个国家的周边国家列表

下面的fetchCountry函数从示例3中的api获得国家信息,其中的参数alpha3Code 是代指该国家的国家代码,以下是代码

// Task 4: 获得中国周边的邻国信息
const fetchCountry = async (alpha3Code) => {
  try {
    const res = await fetch(
      `https://restcountries.eu/rest/v2/alpha/${alpha3Code}`
    );

    const data = await res.json();

    return data;
  } catch (error) {
    console.log(error);
  }
};
Copy after login

下面让我们创建一个fetchCountryAndNeighbors函数,通过传递cn作为alpha3code来获取中国的信息。

const fetchCountryAndNeighbors = async () => {
  const china= await fetchCountry("cn");

  console.log(china);
};

fetchCountryAndNeighbors();
Copy after login

在控制台中,我们看看对象内容:  

在对象中,有一个border属性,它是中国周边邻国的alpha3codes列表。

现在,如果我们尝试通过以下方式获取邻国信息。

const neighbors = 
    china.borders.map((border) => fetchCountry(border));
Copy after login

neighbors是一个Promise对象的数组。

当处理一个数组的Promise时,我们需要使用Promise.all。

const fetchCountryAndNeigbors = async () => {
  const china = await fetchCountry("cn");

  const neighbors = await Promise.all(
    china.borders.map((border) => fetchCountry(border))
  );

  console.log(neighbors);
};

fetchCountryAndNeigbors();
Copy after login

在控制台中,我们应该能够看到国家/地区对象列表。

以下是示例4的所有代码,供您参考:

const fetchCountry = async (alpha3Code) => {
  try {
    const res = await fetch(
      `https://restcountries.eu/rest/v2/alpha/${alpha3Code}`
    );
    const data = await res.json();
    return data;
  } catch (error) {
    console.log(error);
  }
};

const fetchCountryAndNeigbors = async () => {
  const china = await fetchCountry("cn");
  const neighbors = await Promise.all(
    china.borders.map((border) => fetchCountry(border))
  );
  console.log(neighbors);
};

fetchCountryAndNeigbors();
Copy after login

总结

完成这4个示例后,你可以看到Promise在处理异步操作或不是同时发生的事情时很有用。相信在不断的实践中,对它的理解会越深、越强,希望这篇文章能对大家理解Promise和Async/Await带来一些帮助。

以下是本文中使用的代码:

https://files.cnblogs.com/files/powertoolsteam/Promise-Async-Await-main.zip

原文出处:https://www.freecodecamp.org/news/learn-promise-async-await-in-20-minutes/

更多编程相关知识,请访问:编程视频!!

The above is the detailed content of Quickly learn Promise and Async/Await in JavaScript. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:cnblogs.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template