JavaScript異步Promise、Async、await使用舉例詳解
一、JS里的同步異步
fun1(); fun2(); fun3();
如以上代碼,在同步情況下三個(gè)函數(shù)應(yīng)該是依次執(zhí)行的,fun1執(zhí)行完執(zhí)行fun2,最終執(zhí)行fun3。
什么是異步呢?異步就是大家各做各的,互不干擾,無(wú)需互相等待。
但需注意,各做各的,并不意味著亂序。它依然是順序執(zhí)行的。只不過,fun1沒執(zhí)行完,fun2已經(jīng)開始執(zhí)行了。
JS里的常見異步函數(shù)有:settimeout、fetch、setInterval等。
二、Promise
Promise中文意思是承諾,在JS中,可以通俗理解為:把這個(gè)任務(wù)(函數(shù))交給我,我來(lái)完成。
1、狀態(tài)
Promise 的三種狀態(tài):pending(等待中)、fulfilled(成功)、rejected(失?。?,且狀態(tài)改變是不可逆的。
const p=new Promise((resolve,reject)=>{ resolve("你的成功結(jié)果") //執(zhí)行更改后Promise狀態(tài)變成fulfilled //reject("失敗的結(jié)果") //執(zhí)行更改后Promise狀態(tài)變成rejected //throw 1 //拋出異常和reject的效果一樣 }) p.then(res=>res) //then直接返回會(huì)返回包含返回結(jié)果的Promise對(duì)象,可以通過.then()繼續(xù)獲取 .then(res=>{ //res對(duì)應(yīng)resolve里的值 console.log("fulfilled狀態(tài)時(shí)打印") //以下執(zhí)行可以返回狀態(tài)為rejected的Promise給下一級(jí)繼續(xù)執(zhí)行 return new Promise((resolve,reject)=>reject("執(zhí)行出錯(cuò)")) }).catch(error=>{ //error對(duì)應(yīng)reject里的內(nèi)容 console.log("rejected狀態(tài)時(shí)打印") }).finally(()=>{ console.log("無(wú)論成功還是失敗都會(huì)打印") })
2、all()、race()、any()
先一句話描述以下Promise.all()、Promise.race()、Promise.any()的區(qū)別:
(1) Promise.all() 中的Promise序列會(huì)全部執(zhí)行通過才認(rèn)為是成功,否則認(rèn)為是失??;
(2) Promise.race() 中Promise序列中第一個(gè)執(zhí)行完畢的是通過,則認(rèn)為是成功,如果第一個(gè)執(zhí)行完畢的Promise是rejected,則認(rèn)為失??;
(3) Promise.any() 中Promise序列只有有一個(gè)執(zhí)行通過,則認(rèn)為成功,如果全部拒絕,則認(rèn)為失敗。
用一張圖來(lái)說(shuō)明all()、any():
any和all類似,區(qū)別在于any只要有一個(gè)成功就返回成功的結(jié)果。
用一張圖來(lái)說(shuō)明race():
Both resolve, but promise2 is faster ,從這里可以看出端倪。顧名思義,Promse.race 就是賽跑的意思,意思就是說(shuō),Promise.race([p1, p2, p3])里面哪個(gè)結(jié)果獲得的快,就返回那個(gè)結(jié)果,不管結(jié)果本身是成功狀態(tài)還是失敗狀態(tài)。
3、簡(jiǎn)單案例
通過簡(jiǎn)單案例了解:
//Promise用法 const param1 = "normal"; const param2 = "error"; // 第二種情況 //1. 創(chuàng)建Promise類的對(duì)象 const promise01 = new Promise(function customFun(successFun, failFun) { if (param1 === "normal") { successFun("自定義成功的函數(shù)執(zhí)行了!") } else { //失敗和成功的邏輯都是自定義的 failFun("自定義失敗的函數(shù)執(zhí)行了!") } }) const promise02 = new Promise(function customFun(successFun, failFun) { // 第二種情況 if (param2 === "normal") { successFun("自定義成功的函數(shù)執(zhí)行了!") } else { //失敗和成功的邏輯都是自定義的 failFun("自定義失敗的函數(shù)執(zhí)行了!") } }) //2. 執(zhí)行Promise的返回結(jié)果 promise01.then(result => { console.log(result) }).catch(error => { console.log(error) }) promise02.then(result => { // 第二種情況 console.log(result) }).catch(error => { console.log(error) })
可以看到控制臺(tái)打印如下:
第一種情況走自定義成功的邏輯,第二種情況走自定義失敗的邏輯。
4、異步執(zhí)行案例
//異步常見案例 const promise03 = new Promise(() => { console.log("This is Promise constructor.") setTimeout(() => { console.log("Timeout executed!") }, 3000) }) promise03.then(result => { console.log(result) }) console.log("Test Demo.")
控制臺(tái)輸出:
可以清晰地看到,在Promise被執(zhí)行時(shí),構(gòu)造信息就已經(jīng)打印了,之后,順序執(zhí)行了Test Demo, 等待3秒后系統(tǒng)再執(zhí)行了setTimout里的邏輯。
5、解決異步嵌套繁瑣的場(chǎng)景
//Promise來(lái)規(guī)范Timeout嵌套調(diào)用的閱讀性差問題 const promise04 = new Promise((successFun, failFun) => { setTimeout(() => { successFun("timeout 333") }, 3000) }) const promise05 = promise04.then((res) => { console.log(res) return new Promise((successFun, failFun) => { setTimeout(() => { successFun("timeout 222") }, 2000) }) }) promise05.then(res => { console.log(res) }) console.log("Test Demo.")
控制臺(tái)打印:
可以看到,首先打印了Test Demo,3秒后執(zhí)行了第一各Promise里的內(nèi)容,執(zhí)行完第一個(gè)Promise里的內(nèi)容后,再過2秒執(zhí)行了第二各Promise里的內(nèi)容。這比setTimout的多層嵌套,可讀性更好。
三、async和await
async必須用來(lái)修飾函數(shù),用來(lái)表示該函數(shù)是一個(gè)異步函數(shù),await必須和async配套使用。await專門用來(lái)修飾Promise的實(shí)例化對(duì)象。
1、async返回類型
//async有返回類型時(shí),以Promise形式返回 async function asyncDemo01Fun(){ return "Demo01" } async function asyncDemo02Fun(){ return Promise.resolve("Demo02") } console.log(asyncDemo01Fun()) console.log(asyncDemo02Fun())
打印結(jié)果:
可以看到,直接返回結(jié)果和利用Promise.resolve返回結(jié)果是一樣的。
由async修飾的函數(shù),在有返回值時(shí)都會(huì)直接返回Promise對(duì)象,而非直接返回值。
2、async與await結(jié)合使用的簡(jiǎn)單案例
//async和await的案例Demo async function asyncFun1() { const p = new Promise((successFun, failFun) => { setTimeout(() => { successFun({num: 1}) }, 3000) }) let obj = await p; console.log(obj) } asyncFun1() console.log("Test Demo.")
打印結(jié)果:
可以看到,當(dāng)有await修飾Promise返回對(duì)象時(shí),會(huì)等待Promise對(duì)象執(zhí)行完成后,再返回結(jié)果給對(duì)象,最終將獲取到的對(duì)象值在3秒后打印。
當(dāng)有await修飾Promise對(duì)象時(shí),系統(tǒng)會(huì)等待返回值后再返回對(duì)象,繼續(xù)執(zhí)行。實(shí)際上是將異步處理的事件處理完成后再繼續(xù)執(zhí)行同步代碼。
3、解決異步嵌套問題
//async和await的案例Demo async function asyncFun2() { const p1 = new Promise((successFun, failFun) => { setTimeout(() => { successFun("Demo 333") }, 3000) }) let obj1 = await p1; console.log(obj1) const p2 = new Promise((successFun, failFun) => { setTimeout(() => { successFun("Demo 222") }, 2000) }) let obj2 = await p2; console.log(obj2) } asyncFun2() console.log("Test Demo.")
控制臺(tái)打印:
可以看到,首先打印了Test Demo,3秒后執(zhí)行了第一各Promise里的內(nèi)容,執(zhí)行完第一個(gè)Promise里的內(nèi)容后,再過2秒執(zhí)行了第二各Promise里的內(nèi)容。這比setTimout的多層嵌套,可讀性更好。
4、批量請(qǐng)求優(yōu)化
以下是同步獲取請(qǐng)求結(jié)果的案例:
const batchReq=async ()=>{ const url="https://example.com/api/demo" let rep1=await fetch(`${url}/1/`) let json1=await rep1.json() let name1=await json1.data.name let rep2=await fetch(`${url}/2/`) let json2=await rep1.json() let name2=await json1.data.name let rep3=await fetch(`${url}/3/`) let json3=await rep1.json() let name3=await json1.data.name console.log(name1) console.log(name2) console.log(name3) }
以上代碼在執(zhí)行的過程中,由于加了await進(jìn)行修飾,會(huì)依次進(jìn)行請(qǐng)求,1執(zhí)行完2執(zhí)行最后3執(zhí)行。
如要實(shí)現(xiàn)批量請(qǐng)求同時(shí)處理,可以參考以下代碼:
const batchReq = async () => { try { const url = "https://example.com/api/demo" let resp = await Promise.all([fetch(`${url}/1/`), fetch(`${url}/2/`), fetch(`${url}/3/`)]) let jsons = resp.map(res => res.json()) let values = await Promise.all(jsons) values.map(value => { console.log(value.data.name) }) } catch (error) { console.log(error) } }
這樣寫便可以批量發(fā)送請(qǐng)求了。
總結(jié)
到此這篇關(guān)于JavaScript異步Promise、Async、await使用的文章就介紹到這了,更多相關(guān)JS異步Promise、Async、await內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 詳解JavaScript Promise和Async/Await
- Javascript的promise,async和await的區(qū)別詳解
- 前端常見面試題之a(chǎn)sync/await和promise的區(qū)別
- 細(xì)數(shù)promise與async/await的使用及區(qū)別說(shuō)明
- JavaScript Promise與async/await作用詳細(xì)講解
- js中async/await與Promise的區(qū)別
- Node.js 中正確使用 async/await 與 Promise 對(duì)象配合(操作方法)
- ES6中Promise、async、await用法超詳細(xì)講解指南
相關(guān)文章
微信小程使用swiper組件實(shí)現(xiàn)圖片輪播切換顯示功能【附源碼下載】
這篇文章主要介紹了微信小程使用swiper組件實(shí)現(xiàn)圖片輪播切換顯示功能,涉及swiper組件相關(guān)屬性使用技巧,并附帶源碼供讀者下載參考,需要的朋友可以參考下2017-12-12Sample script that deletes a SQL Server database
Sample script that deletes a SQL Server database...2007-06-06JavaScript實(shí)現(xiàn)左右點(diǎn)擊切換圖片
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)簡(jiǎn)易左右點(diǎn)擊切換圖片,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07js中bool值的轉(zhuǎn)換及“&&”、“||”、 “!!”詳解
這篇文章主要給大家介紹了關(guān)于js中bool值的轉(zhuǎn)換方法以及"&&" 、"||"、 "!!"的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友下面來(lái)一起看看吧。2017-12-12JS前端知識(shí)點(diǎn)總結(jié)之頁(yè)面加載事件,數(shù)組操作,DOM節(jié)點(diǎn)操作,循環(huán)和分支
這篇文章主要介紹了JS前端知識(shí)點(diǎn)總結(jié)之頁(yè)面加載事件,數(shù)組操作,DOM節(jié)點(diǎn)操作,循環(huán)和分支,結(jié)合實(shí)例形式總結(jié)分析了JS頁(yè)面加載事件,數(shù)組操作,DOM節(jié)點(diǎn)操作,循環(huán)和分支所涉及的相關(guān)事件、函數(shù)及操作注意事項(xiàng),需要的朋友可以參考下2019-07-07微信小程序手動(dòng)添加收貨地址省市區(qū)聯(lián)動(dòng)
這篇文章主要為大家詳細(xì)介紹了微信小程序手動(dòng)添加收貨地址省市區(qū)聯(lián)動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05javascript 單例模式詳解及簡(jiǎn)單實(shí)例
這篇文章主要介紹了javascript 單例模式詳解及簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-02-02微信小程序三級(jí)聯(lián)動(dòng)選擇器使用方法
這篇文章主要為大家詳細(xì)介紹了微信小程序三級(jí)聯(lián)動(dòng)選擇器使用方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-02-02