电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

詳解JavaScript Promise和Async/Await

瀏覽:11日期:2023-10-01 15:01:22
概述

一般在開發(fā)中,查詢網(wǎng)絡(luò)API操作時(shí)往往是比較耗時(shí)的,這意味著可能需要一段時(shí)間的等待才能獲得響應(yīng)。因此,為了避免程序在請(qǐng)求時(shí)無響應(yīng)的情況,異步編程就成為了開發(fā)人員的一項(xiàng)基本技能。

在JavaScript中處理異步操作時(shí),通常我們經(jīng)常會(huì)聽到 'Promise '這個(gè)概念。但要理解它的工作原理及使用方法可能會(huì)比較抽象和難以理解。

四個(gè)示例

那么,在本文中我們將會(huì)通過實(shí)踐的方式讓你能更快速的理解它們的概念和用法,所以與許多傳統(tǒng)干巴巴的教程都不同,我們將通過以下四個(gè)示例開始:

示例1:用生日解釋Promise的基礎(chǔ)知識(shí) 示例2:一個(gè)猜數(shù)字的游戲 示例3:從Web API中獲取國(guó)家信息 示例4:從Web API中獲取一個(gè)國(guó)家的周邊國(guó)家列表示例1:用生日解釋Promise基礎(chǔ)知識(shí)

首先,我們先來看看Promise的基本形態(tài)是什么樣的。

Promise執(zhí)行時(shí)分三個(gè)狀態(tài):pending(執(zhí)行中)、fulfilled(成功)、rejected(失敗)。

new Promise(function(resolve, reject) { if (/* 異步操作成功 */) {resolve(value); //將Promise的狀態(tài)由padding改為fulfilled } else {reject(error); //將Promise的狀態(tài)由padding改為rejected }})實(shí)現(xiàn)時(shí)有三個(gè)原型方法then、catch、finallypromise.then((result) => { //promise被接收或拒絕繼續(xù)執(zhí)行的情況}).catch((error) => { //promise被拒絕的情況}).finally (() => { //promise完成時(shí),無論如何都會(huì)執(zhí)行的情況})

基本形態(tài)介紹完成了,那么我們下面開始看看下面的示例吧。

用戶故事:我的朋友Kayo答應(yīng)在兩周后在我的生日Party上為我做一個(gè)蛋糕。

如果一切順利且Kayo沒有生病的話,我們就會(huì)獲得一定數(shù)量的蛋糕,但如果Kayo生病了,我們就沒有蛋糕了。但不論有沒有蛋糕,我們?nèi)匀粫?huì)開一個(gè)生日Party。

所以對(duì)于這個(gè)示例,我們將如上的背景故事翻譯成JS代碼,首先讓我們先創(chuàng)建一個(gè)返回Promise的函數(shù)。

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

在JavaScript中,我們可以使用new Promise()創(chuàng)建一個(gè)新的Promise,它接受一個(gè)參數(shù)為:(resolve,reject)=>{} 的函數(shù)。

在此函數(shù)中,resolve和reject是默認(rèn)提供的回調(diào)函數(shù)。讓我們仔細(xì)看看上面的代碼。

當(dāng)我們運(yùn)行onMyBirthday函數(shù)2000ms后。

如果Kayo沒有生病,那么我們就以2為參數(shù)執(zhí)行resolve函數(shù) 如果Kayo生病了,那么我們用new Error('I am sad')作為參數(shù)執(zhí)行reject。盡管您可以將任何要拒絕的內(nèi)容作為參數(shù)傳遞,但建議將其傳遞給Error對(duì)象。

現(xiàn)在,因?yàn)閛nMyBirthday()返回的是一個(gè)Promise,我們可以訪問then、catch和finally方法。我們還可以訪問早些時(shí)候在then和catch中使用傳遞給resolve和reject的參數(shù)。

讓我們通過如下代碼來理解概念

如果Kayo沒有生病

onMyBirthday(false) .then((result) => { console.log(`I have ${result} cakes`); // 控制臺(tái)打印“I have 2 cakes” }) .catch((error) => { console.log(error); // 不執(zhí)行 }) .finally(() => { console.log('Party'); // 控制臺(tái)打印“Party” });

如果Kayo生病

onMyBirthday(true) .then((result) => { console.log(`I have ${result} cakes`); // 不執(zhí)行 }) .catch((error) => { console.log(error); // 控制臺(tái)打印“我很難過” }) .finally(() => { console.log('Party'); // 控制臺(tái)打印“Party” });

相信通過這個(gè)例子你能了解Promise的基本概念。

示例2:一個(gè)猜數(shù)字的游戲

基本需求:

用戶可以輸入任意數(shù)字 系統(tǒng)從1到6中隨機(jī)生成一個(gè)數(shù)字 如果用戶輸入數(shù)字等于系統(tǒng)隨機(jī)數(shù),則給用戶2分 如果用戶輸入數(shù)字與系統(tǒng)隨機(jī)數(shù)相差1,給用戶1分,否則,給用戶0分 用戶想玩多久就玩多久

對(duì)于上面的需求,我們首先創(chuàng)建一個(gè)enterNumber函數(shù)并返回一個(gè)Promise:

const enterNumber = () => { return new Promise((resolve, reject) => { // 從這開始編碼 });};

我們要做的第一件事是向用戶索要一個(gè)數(shù)字,并在1到6之間隨機(jī)選擇一個(gè)數(shù)字:

const enterNumber = () => { return new Promise((resolve, reject) => { const userNumber = Number(window.prompt('Enter a number (1 - 6):')); // 向用戶索要一個(gè)數(shù)字 const randomNumber = Math.floor(Math.random() * 6 + 1); // 選擇一個(gè)從1到6的隨機(jī)數(shù) });};

當(dāng)用戶輸入一個(gè)不是數(shù)字的值。這種情況下,我們調(diào)用reject函數(shù),并拋出錯(cuò)誤:

const enterNumber = () => { return new Promise((resolve, reject) => { const userNumber = Number(window.prompt('Enter a number (1 - 6):')); // 向用戶索要一個(gè)數(shù)字 const randomNumber = Math.floor(Math.random() * 6 + 1); //選擇一個(gè)從1到6的隨機(jī)數(shù) if (isNaN(userNumber)) { reject(new Error('Wrong Input Type')); // 當(dāng)用戶輸入的值非數(shù)字,拋出異常并調(diào)用reject函數(shù) } });};

下面,我們需要檢查userNumber是否等于RanomNumber,如果相等,我們給用戶2分,然后我們可以執(zhí)行resolve函數(shù)來傳遞一個(gè)object { points: 2, randomNumber } 對(duì)象。

如果userNumber與randomNumber相差1,那么我們給用戶1分。否則,我們給用戶0分。

return new Promise((resolve, reject) => { const userNumber = Number(window.prompt('Enter a number (1 - 6):')); // 向用戶索要一個(gè)數(shù)字 const randomNumber = Math.floor(Math.random() * 6 + 1); // 選擇一個(gè)從1到6的隨機(jī)數(shù) if (isNaN(userNumber)) { reject(new Error('Wrong Input Type')); // 當(dāng)用戶輸入的值非數(shù)字,拋出異常并調(diào)用reject函數(shù) } 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, }); }});

下面,讓我們?cè)賱?chuàng)建一個(gè)函數(shù)來詢問用戶是否想繼續(xù)游戲:

const continueGame = () => { return new Promise((resolve) => { if (window.confirm('Do you want to continue?')) { // 向用戶詢問是否要繼續(xù)游戲 resolve(true); } else { resolve(false); } });};

為了不使游戲強(qiáng)制結(jié)束,我們創(chuàng)建的Promise沒有使用Reject回調(diào)。

下面,我們創(chuàng)建一個(gè)函數(shù)來處理猜數(shù)字邏輯:

const handleGuess = () => { enterNumber() // 返回一個(gè)Promise對(duì)象 .then((result) => { alert(`Dice: ${result.randomNumber}: you got ${result.points} points`); // 當(dāng)resolve運(yùn)行時(shí),我們得到用戶得分和隨機(jī)數(shù) // 向用戶詢問是否要繼續(xù)游戲 continueGame().then((result) => {if (result) { handleGuess(); // If yes, 游戲繼續(xù)} else { alert('Game ends'); // If no, 彈出游戲結(jié)束框} }); }) .catch((error) => alert(error));}; handleGuess(); // 執(zhí)行handleGuess 函數(shù)

在這當(dāng)我們調(diào)用handleGuess函數(shù)時(shí),enterNumber()返回一個(gè)Promise對(duì)象。

如果Promise狀態(tài)為resolved,我們就調(diào)用then方法,向用戶告知競(jìng)猜結(jié)果與得分,并向用戶詢問是否要繼續(xù)游戲。

如果Promise狀態(tài)為rejected,我們將顯示一條用戶輸入錯(cuò)誤的信息。

不過,這樣的代碼雖然能解決問題,但讀起來還是有點(diǎn)困難。讓我們后面將使用async/await 對(duì)hanldeGuess進(jìn)行重構(gòu)。

網(wǎng)上對(duì)于 async/await 的解釋已經(jīng)很多了,在這我想用一個(gè)簡(jiǎn)單概括的說法來解釋:async/await就是可以把復(fù)雜難懂的異步代碼變成類同步語(yǔ)法的語(yǔ)法糖。

下面開始看重構(gòu)后代碼吧:

const handleGuess = async () => { try { const result = await enterNumber(); // 代替then方法,我們只需將await放在promise前,就可以直接獲得結(jié)果 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函數(shù)來替代 alert(error); }};

通過在函數(shù)前使用async關(guān)鍵字,我們創(chuàng)建了一個(gè)異步函數(shù),在函數(shù)內(nèi)的使用方法較之前有如下不同:

和then函數(shù)不同,我們只需將await關(guān)鍵字放在Promise前,就可以直接獲得結(jié)果。 我們可以使用try, catch語(yǔ)法來代替promise中的catch方法。

下面是我們重構(gòu)后的完整代碼,供參考:

const enterNumber = () => { return new Promise((resolve, reject) => { const userNumber = Number(window.prompt('Enter a number (1 - 6):')); // 向用戶索要一個(gè)數(shù)字 const randomNumber = Math.floor(Math.random() * 6 + 1); // 系統(tǒng)隨機(jī)選取一個(gè)1-6的數(shù)字 if (isNaN(userNumber)) { reject(new Error('Wrong Input Type')); // 如果用戶輸入非數(shù)字拋出錯(cuò)誤 } if (userNumber === randomNumber) { // 如果用戶猜數(shù)字正確,給用戶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?')) { // 向用戶詢問是否要繼續(xù)游戲 resolve(true); } else { resolve(false); } });}; const handleGuess = async () => { try { const result = await enterNumber(); // await替代了then函數(shù) 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函數(shù)來替代 alert(error); }}; handleGuess(); // 執(zhí)行handleGuess 函數(shù)

我們已經(jīng)完成了第二個(gè)示例,接下來讓我們開始看看第三個(gè)示例。

示例3:從Web API中獲取國(guó)家信息

一般當(dāng)從API中獲取數(shù)據(jù)時(shí),開發(fā)人員會(huì)精彩使用Promises。如果在新窗口打開https://restcountries.eu/rest/v2/alpha/cn,你會(huì)看到JSON格式的國(guó)家數(shù)據(jù)。

通過使用Fetch API,我們可以很輕松的獲得數(shù)據(jù),以下是代碼:

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();

現(xiàn)在我們獲得了所需的國(guó)家/地區(qū)數(shù)據(jù),讓我們轉(zhuǎn)到最后一項(xiàng)任務(wù)。

示例4:從Web API中獲取一個(gè)國(guó)家的周邊國(guó)家列表

下面的fetchCountry函數(shù)從示例3中的api獲得國(guó)家信息,其中的參數(shù)alpha3Code 是代指該國(guó)家的國(guó)家代碼,以下是代碼

// Task 4: 獲得中國(guó)周邊的鄰國(guó)信息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); }};

下面讓我們創(chuàng)建一個(gè)fetchCountryAndNeighbors函數(shù),通過傳遞cn作為alpha3code來獲取中國(guó)的信息。

const fetchCountryAndNeighbors = async () => { const china= await fetchCountry('cn'); console.log(china);}; fetchCountryAndNeighbors();

在控制臺(tái)中,我們看看對(duì)象內(nèi)容:

詳解JavaScript Promise和Async/Await

在對(duì)象中,有一個(gè)border屬性,它是中國(guó)周邊鄰國(guó)的alpha3codes列表。

現(xiàn)在,如果我們嘗試通過以下方式獲取鄰國(guó)信息。

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

neighbors是一個(gè)Promise對(duì)象的數(shù)組。

當(dāng)處理一個(gè)數(shù)組的Promise時(shí),我們需要使用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();

在控制臺(tái)中,我們應(yīng)該能夠看到國(guó)家/地區(qū)對(duì)象列表。

詳解JavaScript Promise和Async/Await

以下是示例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();總結(jié)

完成這4個(gè)示例后,你可以看到Promise在處理異步操作或不是同時(shí)發(fā)生的事情時(shí)很有用。相信在不斷的實(shí)踐中,對(duì)它的理解會(huì)越深、越強(qiáng),希望這篇文章能對(duì)大家理解Promise和Async/Await帶來一些幫助。

以下是本文中使用的代碼:https://files.cnblogs.com/files/powertoolsteam/Promise-Async-Await-main.zip

以上就是詳解JavaScript Promise和Async/Await的詳細(xì)內(nèi)容,更多關(guān)于JavaScript Promise和Async/Await的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: JavaScript
相關(guān)文章:
主站蜘蛛池模板: 美名宝起名网-在线宝宝、公司、起名平台| 水轮机密封网 | 水轮机密封产品研发生产厂家 | Safety light curtain|Belt Sway Switches|Pull Rope Switch|ultrasonic flaw detector-Shandong Zhuoxin Machinery Co., Ltd | pos机办理,智能/扫码/二维码/微信支付宝pos机-北京万汇通宝商贸有限公司 | 武汉森源蓝天环境科技工程有限公司-为环境污染治理提供协同解决方案 | 恒温水槽与水浴锅-上海熙浩实业有限公司 | 熔体泵|换网器|熔体齿轮泵|熔体计量泵厂家-郑州巴特熔体泵有限公司 | 全自动包衣机-无菌分装隔离器-浙江迦南科技股份有限公司 | 印刷人才网 印刷、包装、造纸,中国80%的印刷企业人才招聘选印刷人才网! | 氨水-液氨-工业氨水-氨水生产厂家-辽宁顺程化工| 不锈钢复合板厂家_钛钢复合板批发_铜铝复合板供应-威海泓方金属复合材料股份有限公司 | 哈希余氯测定仪,分光光度计,ph在线监测仪,浊度测定仪,试剂-上海京灿精密机械有限公司 | 回收二手冲床_金丰旧冲床回收_协易冲床回收 - 大鑫机械设备 | 东莞市踏板石餐饮管理有限公司_正宗桂林米粉_正宗桂林米粉加盟_桂林米粉加盟费-东莞市棒子桂林米粉 | 耐高温风管_耐高温软管_食品级软管_吸尘管_钢丝软管_卫生级软管_塑料波纹管-东莞市鑫翔宇软管有限公司 | 低浓度恒温恒湿称量系统,强光光照培养箱-上海三腾仪器有限公司 | 电脑知识|软件|系统|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网 | 施工围挡-施工PVC围挡-工程围挡-深圳市旭东钢构技术开发有限公司 | 北京京云律师事务所 | 篮球地板厂家_舞台木地板品牌_体育运动地板厂家_凯洁地板 | 利浦顿蒸汽发生器厂家-电蒸汽发生器/燃气蒸汽发生器_湖北利浦顿热能科技有限公司官网 | 【中联邦】增稠剂_增稠粉_水性增稠剂_涂料增稠剂_工业增稠剂生产厂家 | 首页_欧瑞传动官方网站--主营变频器、伺服系统、新能源、软起动器、PLC、HMI | 小型高低温循环试验箱-可程式高低温湿热交变试验箱-东莞市拓德环境测试设备有限公司 | 天津热油泵_管道泵_天津高温热油泵-天津市金丰泰机械泵业有限公司【官方网站】 | 博客-悦享汽车品质生活| 连续油炸机,全自动油炸机,花生米油炸机-烟台茂源食品机械制造有限公司 | 高压管道冲洗清洗机_液压剪叉式升降机平台厂家-林君机电 | PCB接线端子_栅板式端子_线路板连接器_端子排生产厂家-置恒电气 喷码机,激光喷码打码机,鸡蛋打码机,手持打码机,自动喷码机,一物一码防伪溯源-恒欣瑞达有限公司 假肢-假肢价格-假肢厂家-河南假肢-郑州市力康假肢矫形器有限公司 | 杭州代理记账费用-公司注销需要多久-公司变更监事_杭州福道财务管理咨询有限公司 | 湖南印刷厂|长沙印刷公司|画册印刷|挂历印刷|台历印刷|杂志印刷-乐成印刷 | 天津云仓-天津仓储物流-天津云仓一件代发-顺东云仓 | 风淋室生产厂家报价_传递窗|送风口|臭氧机|FFU-山东盛之源净化设备 | 智能交通网_智能交通系统_ITS_交通监控_卫星导航_智能交通行业 | 复合土工膜厂家|hdpe防渗土工膜|复合防渗土工布|玻璃纤维|双向塑料土工格栅-安徽路建新材料有限公司 | 无硅导热垫片-碳纤维导热垫片-导热相变材料厂家-东莞市盛元新材料科技有限公司 | LHH药品稳定性试验箱-BPS系列恒温恒湿箱-意大利超低温冰箱-上海一恒科学仪器有限公司 | 山东商品混凝土搅拌楼-环保型搅拌站-拌合站-分体仓-搅拌机厂家-天宇 | 手持式3d激光扫描仪-便携式三维立体扫描仪-北京福禄克斯 | 赛默飞Thermo veritiproPCR仪|ProFlex3 x 32PCR系统|Countess3细胞计数仪|371|3111二氧化碳培养箱|Mirco17R|Mirco21R离心机|仟诺生物 | 广州展览设计公司_展台设计搭建_展位设计装修公司-众派展览装饰 广州展览制作工厂—[优简]直营展台制作工厂_展会搭建资质齐全 |