通常在合作开发中,查阅互联网 API 操作形式时常常是较为费时的,这意味著可能将须要一两年的等候就可以赢得积极响应。因而,为的是防止流程在允诺时无积极响应的情形,触发器程式设计就正式成为的是合作开发者的几项基本上知识。
在 JavaScript 中处置触发器操作形式时,通常来说他们时常会听见 “Promise “那个基本上概念。但要认知它的组织工作基本上原理及采用形式可能将会较为抽象化和无法认知。
因而,在责任编辑中他们Sonbhadra透过课堂教学的形式让你能更加速的认知它的基本上概念和用语,因而与很多现代苍白的讲义都相同,他们将透过下列五个实例已经开始:
实例1:用过生日说明Promise的基本上知识实例2:两个猜位数的格斗游戏个北欧国家的邻国条目实例1:用过生日说明Promise基本上知识
具体来说,他们先来看一看Promise的基本上型态是怎样的。
Promise拒绝执行时份五个状况:pending(拒绝执行中)、fulfilled(赢得成功)、rejected(失败)。
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完成时,无论如何都会拒绝执行的情形 })基本上型态介绍完成了,因而他们下面已经开始看一看下面的实例吧。
用户故事:我的朋友Kayo答应在两周后在我的过生日Party上为我做两个蛋糕。
如果一切顺利且Kayo没有生病的话,他们就会赢得一定数量的蛋糕,但如果Kayo生病了,他们就没有蛋糕了。但不论有没有蛋糕,他们仍然会开两个过生日Party。
因而对于那个实例,他们将如上的背景故事翻译成JS代码,具体来说让他们先创建两个返回Promise的函数。
const onMyBirthday = (isKayoSick) => { return new Promise((resolve, reject) => { setTimeout(() => { if (!isKayoSick) { resolve(2); } else{ reject(new Error(“I am sad”)); } }, 2000); }); };在JavaScript中,他们可以采用new Promise()创建两个新的Promise,它接受两个参数为:(resolve,reject)=>{} 的函数。
在此函数中,resolve和reject是默认提供的回调函数。让他们仔细看一看上面的代码。
当他们运行onMyBirthday函数2000ms后。
如果Kayo没有生病,因而他们就以2为参数拒绝执行resolve函数如果Kayo生病了,因而他们用new Error(“I am sad”)作为参数拒绝执行reject。尽管您可以将任何要婉拒的内容作为参数传递,但建议将其传递给Error对象。现在,因为onMyBirthday()返回的是两个Promise,他们可以访问then、catch和finally形式。他们还可以访问早些时候在then和catch中采用传递给resolve和reject的参数。
让他们透过如下代码来认知基本上概念,相信透过那个例子你能了解Promise的基本上基本上概念。
如果Kayo没有生病
onMyBirthday(false) .then((result) => { console.log(`I have ${result} cakes`); // 控制台打印“I have 2 cakes” }) .catch((error) => { console.log(error); // 不拒绝执行 }) .finally(() => { console.log(“Party”); // 控制台打印“Party”});如果Kayo生病
onMyBirthday(true) .then((result) => { console.log(`I have ${result} cakes`); //不拒绝执行 }) .catch((error) => { console.log(error); // 控制台打印“我很难过” }) .finally(() => { console.log(“Party”); //控制台打印“Party” });实例2:两个猜位数的格斗游戏
基本上需求:
用户可以输入任意位数系统从1到6中随机生成两个位数如果用户输入位数等于系统随机数,则给用户2分如果用户输入位数与系统随机数相差1,给用户1分,否则,给用户0分用户想玩多久就玩多久对于上面的需求,他们具体来说创建两个enterNumber函数并返回两个Promise:
const enterNumber = () => { return new Promise((resolve, reject) => { // 从这已经开始编码 }); };他们要做的第一件事是向用户索要两个位数,并在1到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的随机数 }); };当用户输入两个不是位数的值。这种情形下,他们调用reject函数,并抛出错误:
const enterNumber = () => { return new Promise((resolve, reject) => { constuserNumber =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回调。
下面,他们创建两个函数来处置猜位数逻辑:
consthandleGuess =() => { 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 = awaitenterNumber();// await替代了then函数 alert(`Dice: ${result.randomNumber}: you got ${result.points} points`); constisContinuing =await continueGame(); if (isContinuing) { handleGuess(); } else { alert(“Game ends”); } } catch (error) { // catch 形式可以由try, catch函数来替代alert(error); } }; handleGuess();// 拒绝执行handleGuess 函数 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); // Chinas 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 = awaitres.json();return data; } catch (error) { console.log(error); } };下面让他们创建两个fetchCountryAndNeighbors函数,通
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。
constfetchCountryAndNeigbors =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 { constres =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带来一些帮助。
这是责任编辑中采用的代码:Asdkjbasrksbr。