async/await 的基礎使用及原理簡介?https://www.cnblogs.com/zhengyufeng/p/11106901.html
async/await是es7推出的一套關于異步的終極解決方案,為什么要說他是終極解決方案呢惶我?因為他實在是太好用了,而且寫起來還非常的簡單。
一:async/await基礎語法
// 定義一個異步函數(shù)(假設他是一個異步函數(shù))getJSON(){return'JSON'}// 在需要使用上面異步函數(shù)的函數(shù)前面,加上async聲明,聲明這是一個異步函數(shù)asynctestAsync(){// 在異步函數(shù)前面加上await骡和,函數(shù)執(zhí)行就會等待用await聲明的異步函數(shù)執(zhí)行完畢之后,在往下執(zhí)行awaitgetJSON()? ? ...剩下的代碼}
以上就是async/await最基本的用法相寇。
還需要注意的一點就是使用async/await的時候慰于,是無法捕獲錯誤的,這個時候就要用到我們es5里面一個被大家遺忘了的try/catch唤衫,來進行錯誤的捕獲:
asynctestAsync() {try{awaitgetJSON()? }catch(err) {console.log(err)? }? ...剩下的代碼}
注意:
1.async函數(shù)在聲明形式上和普通函數(shù)沒有區(qū)別婆赠,函數(shù)聲明式,函數(shù)表達式战授,對象方法页藻,class方法和箭頭函數(shù)等都可以聲明async函數(shù)。
2.任何一個await語句后面的 Promise 對象變?yōu)閞eject狀態(tài)植兰,那么整個async函數(shù)都會中斷執(zhí)行份帐。
3.async函數(shù)返回的 Promise 對象,必須等到內(nèi)部所有await命令后面的 Promise 對象執(zhí)行完楣导,才會發(fā)生狀態(tài)改變废境,除非遇到return語句或者拋出錯誤。也就是說筒繁,只有async函數(shù)內(nèi)部的異步操作執(zhí)行完噩凹,才會執(zhí)行then方法指定的回調(diào)函數(shù)。
二:async/await
async
async這個單詞大家應該都比較熟悉毡咏,他是英文單詞‘異步’的簡寫驮宴,代表的意思也是異步。
asyncfunctiontestAsync(){return"hello async";}constresult = testAsync();console.log(result);
輸出結果:
Promise{:"hello async"}
可以看出async函數(shù)呕缭,返回的是一個Promise對象
await
await是英文單詞‘等待’的意思堵泽,代表的意思也是等待,那他等的到底是個什么東西呢恢总?還是一個Promise迎罗。
三 async/await和Generator
Generator函數(shù):generator(生成器)是ES6標準引入的新的數(shù)據(jù)類型。一個generator看上去像一個函數(shù)片仿,但可以返回多次纹安。下面面是一個Generator函數(shù)的簡單寫法。
function*Generator(){yield'11111111';yield'22222222'return'3333333';? ? ? ? }letaaa = Generator();
Generator函數(shù)和普通函數(shù)一樣通過函數(shù)名+()去調(diào)用,但是調(diào)用完之后并不執(zhí)行厢岂。它僅僅是創(chuàng)建了一個generator對象光督,還沒有去執(zhí)行它。想要運行Generator函數(shù)塔粒,需要通過遍歷器對象的next方法可帽。
leta = aaa.next()letb = aaa.next()letc = aaa.next()letd = aaa.next()? ? console.log(a,b,c,d) //? {value:"11111111",done:false}? ? {value:"22222222",done:false}? ? ? {value:"3333333",done:true}? ? {value: undefined,done:true}
想要Generator函數(shù)執(zhí)行下一步,必須調(diào)用遍歷器對象的next方法窗怒,使得指針移向下一個狀態(tài)映跟。也就是說,每次調(diào)用next方法扬虚,內(nèi)部指針就從函數(shù)頭部或上一次停下來的地方開始執(zhí)行努隙,直到遇到下一個yield表達式或return語句。由此可見辜昵,Generator 函數(shù)是分段執(zhí)行的荸镊,yield表達式是暫停執(zhí)行的標記,而next方法可以恢復執(zhí)行堪置。也就是上面說的可以交出函數(shù)的執(zhí)行權躬存。
上面對Generator函數(shù)做了一個簡單的介紹,接下來說一下async/await和Generator舀锨。
根據(jù)阮一峰老師的介紹岭洲,async函數(shù)就是Generator函數(shù)的語法糖。
圖片:
代碼上看起來坎匿,async函數(shù)就是將 Generator 函數(shù)的星號(*)替換成async盾剩,將yield替換成await。
實際上async函數(shù)對Generator函數(shù)的改進替蔬,體現(xiàn)在一下四點:
1.async函數(shù)自帶執(zhí)行器告私,所以執(zhí)行方式和普通函數(shù)的執(zhí)行方式一樣,通過函數(shù)名+()的方式執(zhí)行承桥。
2.async和await比起*和yield在語義上更清楚驻粟。
3.co模塊約定,yield命令后面只能是 Thunk 函數(shù)或 Promise 對象凶异,而async函數(shù)的await命令后面蜀撑,可以是 Promise 對象和原始類型的值(數(shù)值、字符串和布爾值唠帝,但這時會自動轉(zhuǎn)成立即 resolved 的 Promise 對象)屯掖。
4.async函數(shù)的返回值是 Promise 對象玄柏,這比 Generator 函數(shù)的返回值是 Iterator 對象方便多了襟衰。你可以用then方法指定下一步的操作。
進一步說粪摘,async函數(shù)完全可以看作多個異步操作瀑晒,包裝成的一個 Promise 對象绍坝,而await命令就是內(nèi)部then命令的語法糖。
四:async/await和Promise
上面說了async/await和Generator的關系苔悦,這里再說一下和Promise的關系轩褐,async/await其實是基于Promise的。async函數(shù)其實是把Promise包裝了一下玖详。
下面是一個async/await的寫法:
getConstant() {return1}asyncgetAsyncConstant() {return1}asyncgetPromise() {returnnewPromise((resolved, rejected)=>{? ? resolved(1)? }); }asynctest() {leta =2letc =1awaitgetConstant();letd =3awaitgetPromise();letd =4awaitgetAsyncConstant();return2}
上面的代碼其實真正的在解析執(zhí)行的時候是這樣的:
functiongetConstant(){return1;}functiongetAsyncConstant(){returnPromise.resolve().then(function(){return1;? });}functiongetPromise(){returnPromise.resolve().then(function(){returnnewPromise((resolved, rejected) =>{? ? resolved(1);? });? });}? test() {returnPromise.resolve().then(function(){leta =2;letc =1;returngetConstant();? ? }).then(function(){letd =3;returngetPromise();? ? }).then(function(){letd =4;returngetAsyncConstant();? ? }).then(function(){return2;? ? }); }
通過上面的代碼可以看出async/await的本身還是基于Promise的把介。
因為await本身返回的也是一個Promise,它只是把await后面的代碼放到了await返回的Promise的.then后面,以此來實現(xiàn)的蟋座。
做個練習:
functiongetJson(){returnnewPromise((reslove,reject) =>{? ? ? ? setTimeout(function(){console.log(2)? ? ? ? ? reslove(2)? ? ? ? },2000)? ? ? })? ? }asyncfunctiontestAsync(){awaitgetJson()console.log(3)? ? }? ? testAsync()
上面的代碼是會先打印2還是3拗踢?
答案是2,3
看過上面的童鞋應該知道其實他的真實代碼是這樣的:
functiongetJson(){returnnewPromise((reslove,reject) =>{? ? ? setTimeout(function(){console.log(2)? ? ? ? reslove()? ? ? },2000)? ? })}functiontestAsync(){returnnewPromise((reslove,reject) =>{? ? ? ? getJson().then(function(res){console.log(3)? ? ? ? })? ? })}testAsync()