JavaScript異步Promise、Async、await使用舉例詳解
一、JS里的同步異步
fun1(); fun2(); fun3();
如以上代碼,在同步情況下三個函數(shù)應該是依次執(zhí)行的,fun1執(zhí)行完執(zhí)行fun2,最終執(zhí)行fun3。
什么是異步呢?異步就是大家各做各的,互不干擾,無需互相等待。
但需注意,各做各的,并不意味著亂序。它依然是順序執(zhí)行的。只不過,fun1沒執(zhí)行完,fun2已經(jīng)開始執(zhí)行了。
JS里的常見異步函數(shù)有:settimeout、fetch、setInterval等。
二、Promise
Promise中文意思是承諾,在JS中,可以通俗理解為:把這個任務(函數(shù))交給我,我來完成。
1、狀態(tài)
Promise 的三種狀態(tài):pending(等待中)、fulfilled(成功)、rejected(失?。覡顟B(tài)改變是不可逆的。
const p=new Promise((resolve,reject)=>{ resolve("你的成功結果") //執(zhí)行更改后Promise狀態(tài)變成fulfilled //reject("失敗的結果") //執(zhí)行更改后Promise狀態(tài)變成rejected //throw 1 //拋出異常和reject的效果一樣 }) p.then(res=>res) //then直接返回會返回包含返回結果的Promise對象,可以通過.then()繼續(xù)獲取 .then(res=>{ //res對應resolve里的值 console.log("fulfilled狀態(tài)時打印") //以下執(zhí)行可以返回狀態(tài)為rejected的Promise給下一級繼續(xù)執(zhí)行 return new Promise((resolve,reject)=>reject("執(zhí)行出錯")) }).catch(error=>{ //error對應reject里的內容 console.log("rejected狀態(tài)時打印") }).finally(()=>{ console.log("無論成功還是失敗都會打印") })
2、all()、race()、any()
先一句話描述以下Promise.all()、Promise.race()、Promise.any()的區(qū)別:
(1) Promise.all() 中的Promise序列會全部執(zhí)行通過才認為是成功,否則認為是失?。?/p>
(2) Promise.race() 中Promise序列中第一個執(zhí)行完畢的是通過,則認為是成功,如果第一個執(zhí)行完畢的Promise是rejected,則認為失敗;
(3) Promise.any() 中Promise序列只有有一個執(zhí)行通過,則認為成功,如果全部拒絕,則認為失敗。
用一張圖來說明all()、any():
any和all類似,區(qū)別在于any只要有一個成功就返回成功的結果。
用一張圖來說明race():
Both resolve, but promise2 is faster ,從這里可以看出端倪。顧名思義,Promse.race 就是賽跑的意思,意思就是說,Promise.race([p1, p2, p3])里面哪個結果獲得的快,就返回那個結果,不管結果本身是成功狀態(tài)還是失敗狀態(tài)。
3、簡單案例
通過簡單案例了解:
//Promise用法 const param1 = "normal"; const param2 = "error"; // 第二種情況 //1. 創(chuàng)建Promise類的對象 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的返回結果 promise01.then(result => { console.log(result) }).catch(error => { console.log(error) }) promise02.then(result => { // 第二種情況 console.log(result) }).catch(error => { console.log(error) })
可以看到控制臺打印如下:
第一種情況走自定義成功的邏輯,第二種情況走自定義失敗的邏輯。
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.")
控制臺輸出:
可以清晰地看到,在Promise被執(zhí)行時,構造信息就已經(jīng)打印了,之后,順序執(zhí)行了Test Demo, 等待3秒后系統(tǒng)再執(zhí)行了setTimout里的邏輯。
5、解決異步嵌套繁瑣的場景
//Promise來規(guī)范Timeout嵌套調用的閱讀性差問題 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.")
控制臺打?。?/p>
可以看到,首先打印了Test Demo,3秒后執(zhí)行了第一各Promise里的內容,執(zhí)行完第一個Promise里的內容后,再過2秒執(zhí)行了第二各Promise里的內容。這比setTimout的多層嵌套,可讀性更好。
三、async和await
async必須用來修飾函數(shù),用來表示該函數(shù)是一個異步函數(shù),await必須和async配套使用。await專門用來修飾Promise的實例化對象。
1、async返回類型
//async有返回類型時,以Promise形式返回 async function asyncDemo01Fun(){ return "Demo01" } async function asyncDemo02Fun(){ return Promise.resolve("Demo02") } console.log(asyncDemo01Fun()) console.log(asyncDemo02Fun())
打印結果:
可以看到,直接返回結果和利用Promise.resolve返回結果是一樣的。
由async修飾的函數(shù),在有返回值時都會直接返回Promise對象,而非直接返回值。
2、async與await結合使用的簡單案例
//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.")
打印結果:
可以看到,當有await修飾Promise返回對象時,會等待Promise對象執(zhí)行完成后,再返回結果給對象,最終將獲取到的對象值在3秒后打印。
當有await修飾Promise對象時,系統(tǒng)會等待返回值后再返回對象,繼續(xù)執(zhí)行。實際上是將異步處理的事件處理完成后再繼續(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.")
控制臺打印:
可以看到,首先打印了Test Demo,3秒后執(zhí)行了第一各Promise里的內容,執(zhí)行完第一個Promise里的內容后,再過2秒執(zhí)行了第二各Promise里的內容。這比setTimout的多層嵌套,可讀性更好。
4、批量請求優(yōu)化
以下是同步獲取請求結果的案例:
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進行修飾,會依次進行請求,1執(zhí)行完2執(zhí)行最后3執(zhí)行。
如要實現(xiàn)批量請求同時處理,可以參考以下代碼:
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ā)送請求了。
總結
到此這篇關于JavaScript異步Promise、Async、await使用的文章就介紹到這了,更多相關JS異步Promise、Async、await內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
微信小程使用swiper組件實現(xiàn)圖片輪播切換顯示功能【附源碼下載】
這篇文章主要介紹了微信小程使用swiper組件實現(xiàn)圖片輪播切換顯示功能,涉及swiper組件相關屬性使用技巧,并附帶源碼供讀者下載參考,需要的朋友可以參考下2017-12-12Sample script that deletes a SQL Server database
Sample script that deletes a SQL Server database...2007-06-06JS前端知識點總結之頁面加載事件,數(shù)組操作,DOM節(jié)點操作,循環(huán)和分支
這篇文章主要介紹了JS前端知識點總結之頁面加載事件,數(shù)組操作,DOM節(jié)點操作,循環(huán)和分支,結合實例形式總結分析了JS頁面加載事件,數(shù)組操作,DOM節(jié)點操作,循環(huán)和分支所涉及的相關事件、函數(shù)及操作注意事項,需要的朋友可以參考下2019-07-07