20分钟带你掌握JS Promise和Async/Await( 二 )


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函数}});};下面,我们需要检查userNumber是否等于RanomNumber,如果相等,我们给用户2分,然后我们可以执行resolve函数来传递一个object { points: 2, randomNumber } 对象 。
如果userNumber与randomNumber相差1,那么我们给用户1分 。否则,我们给用户0分 。
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,});}});下面,让我们再创建一个函数来询问用户是否想继续游戏:
const continueGame = () => {return new Promise((resolve) => {if (window.confirm("Do you want to continue?")) { // 向用户询问是否要继续游戏resolve(true);} else {resolve(false);}});};为了不使游戏强制结束,我们创建的Promise没有使用Reject回调 。
下面,我们创建一个函数来处理猜数字逻辑:
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关键字,我们创建了一个异步函数,在函数内的使用方法较之前有如下不同:

  • 和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 函数


推荐阅读