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:
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完成时,无论如何都会执行的情况 })
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); }); };
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.
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” });
If Kayo is sick
onMyBirthday(true) .then((result) => { console.log(`I have ${result} cakes`); // 不执行 }) .catch((error) => { console.log(error); // 控制台打印“我很难过” }) .finally(() => { console.log("Party"); // 控制台打印“Party” });
I believe you can understand Promise through this example basic concept.
Let’s start with Example 2
Basic requirements:
For the above requirements, we first create an enterNumber function and returns a Promise:
const enterNumber = () => { return new Promise((resolve, reject) => { // 从这开始编码 }); };
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的随机数 }); };
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函数 } }); };
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, }); } });
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); } }); };
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 函数
在这当我们调用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); } };
通过在函数前使用async关键字,我们创建了一个异步函数,在函数内的使用方法较之前有如下不同:
下面是我们重构后的完整代码,供参考:
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 函数
我们已经完成了第二个示例,接下来让我们开始看看第三个示例。
一般当从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();
现在我们获得了所需的国家/地区数据,让我们转到最后一项任务。
下面的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); } };
下面让我们创建一个fetchCountryAndNeighbors函数,通过传递cn作为alpha3code来获取中国的信息。
const fetchCountryAndNeighbors = async () => { const china= await fetchCountry("cn"); console.log(china); }; fetchCountryAndNeighbors();
在控制台中,我们看看对象内容:
在对象中,有一个border属性,它是中国周边邻国的alpha3codes列表。
现在,如果我们尝试通过以下方式获取邻国信息。
const neighbors = china.borders.map((border) => fetchCountry(border));
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();
在控制台中,我们应该能够看到国家/地区对象列表。
以下是示例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();
完成这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!