async/await的基礎(chǔ)用法

async/await的典型應(yīng)用場景

function delay(num){
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      resolve(num*2);
    },2000)
  })
}
async function plus(){
  let a=await delay(2);
  let b=await delay(3);
  let c=await delay(5);
  console.log(a+b+c);
}
plus();//20

一、async/await的優(yōu)點(diǎn)

1)方便級聯(lián)調(diào)用

即調(diào)用依次發(fā)生的場景趋厉;

2)同步代碼編寫方式

Promise使用then函數(shù)進(jìn)行鏈?zhǔn)秸{(diào)用寨闹,一直點(diǎn)點(diǎn)點(diǎn),是一種從左向右的橫向?qū)懛ň耍籥sync/await從上到下繁堡,順序執(zhí)行,就像寫同步代碼一樣乡数,更符合代碼編寫習(xí)慣椭蹄;

3)多個參數(shù)傳遞

Promise的then函數(shù)只能傳遞一個參數(shù),雖然可以通過包裝成對象來傳遞多個參數(shù)净赴,但是會導(dǎo)致傳遞冗余信息绳矩,頻繁的解析又重新組合參數(shù),比較麻煩劫侧;async/await沒有這個限制埋酬,可以當(dāng)做普通的局部變量來處理哨啃,用let或者const定義的塊級變量想怎么用就怎么用,想定義幾個就定義幾個写妥,完全沒有限制拳球,也沒有冗余工作;

4)同步代碼和異步代碼可以一起編寫

使用Promise的時候最好將同步代碼和異步代碼放在不同的then節(jié)點(diǎn)中珍特,這樣結(jié)構(gòu)更加清晰祝峻;async/await整個書寫習(xí)慣都是同步的,不需要糾結(jié)同步和異步的區(qū)別扎筒,當(dāng)然莱找,異步過程需要包裝成一個Promise對象放在await關(guān)鍵字后面;

5)基于協(xié)程

Promise是根據(jù)函數(shù)式編程的范式嗜桌,對異步過程進(jìn)行了一層封裝奥溺,async/await基于協(xié)程的機(jī)制,是真正的“保存上下文骨宠,控制權(quán)切換……控制權(quán)恢復(fù)浮定,取回上下文”這種機(jī)制,是對異步過程更精確的一種描述层亿;

6)async/await是對Promise的優(yōu)化

async/await是基于Promise的桦卒,是進(jìn)一步的一種優(yōu)化,不過在寫代碼時匿又,Promise本身的API出現(xiàn)得很少方灾,很接近同步代碼的寫法;

二碌更、協(xié)程

進(jìn)程>線程>協(xié)程

協(xié)程的意思是多個線程相互協(xié)作完成異步任務(wù)裕偿,大致流程如下:
1)協(xié)程A開始執(zhí)行;
2)協(xié)程A執(zhí)行到一半针贬,進(jìn)入暫停击费,執(zhí)行權(quán)轉(zhuǎn)移到協(xié)程B拢蛋;
3)一段時間后桦他,協(xié)程B交還執(zhí)行權(quán);
4)協(xié)程A恢復(fù)執(zhí)行谆棱;

協(xié)程是一個無優(yōu)先級的子程序調(diào)度組件快压,允許子程序在特定的地點(diǎn)掛起恢復(fù);

線程包含于進(jìn)程垃瞧,協(xié)程包含于線程蔫劣,只要內(nèi)存足夠,一個線程中可以有任意多個協(xié)程个从,但某一個時刻只能有一個協(xié)程在運(yùn)行脉幢,多個協(xié)程分享該線程分配到的計(jì)算機(jī)資源歪沃;

就實(shí)際使用理解來說,協(xié)程允許我們寫同步代碼的邏輯嫌松,卻做著異步的事沪曙,避免了回調(diào)嵌套,使得代碼邏輯清晰萎羔;

何時掛起液走,喚醒協(xié)程:協(xié)程是為了使用異步的優(yōu)勢,異步操作是為了避免IO操作阻塞線程贾陷,那么協(xié)程掛起的時刻應(yīng)該是當(dāng)前協(xié)程發(fā)起異步操作的時候缘眶,而喚醒應(yīng)該在其他協(xié)程退出,并且他的異步操作完成時髓废;

單線程內(nèi)開啟協(xié)程巷懈,一旦遇到io,從應(yīng)用程序級別(而非操作系統(tǒng))控制切換對比操作系統(tǒng)控制線程的切換慌洪,用戶在單線程內(nèi)控制協(xié)程的切換砸喻,優(yōu)點(diǎn)如下:
1)協(xié)程的切換開銷更小,屬于程序級別的切換蒋譬,操作系統(tǒng)完全感知不到割岛,因而更加輕量級;
2)單線程內(nèi)就可以實(shí)現(xiàn)并發(fā)的效果犯助,最大限度地利用cpu癣漆;

協(xié)程的第一大優(yōu)勢是具有極高的執(zhí)行效率,因?yàn)樽映绦蚯袚Q不是線程切換剂买,而是由程序自身控制惠爽,因此沒有線程切換的開銷,和多線程比瞬哼,線程數(shù)量越多婚肆,協(xié)程的性能優(yōu)勢就越明顯;

協(xié)程的第二大優(yōu)勢是不需要多線程的鎖機(jī)制坐慰,因?yàn)橹挥幸粋€線程较性,也不存在同時寫變量沖突,在協(xié)程中控制共享資源不加鎖结胀,只需要判斷狀態(tài)就好了赞咙,所以執(zhí)行效率比多線程高很多;

協(xié)程看上去也是子程序糟港,但執(zhí)行過程中攀操,在子程序內(nèi)部可中斷,然后轉(zhuǎn)而執(zhí)行別的子程序秸抚,在適當(dāng)?shù)臅r候再返回來接著執(zhí)行速和,需要注意的是:在一個子程序中中斷歹垫,去執(zhí)行其他子程序,這并不是函數(shù)調(diào)用颠放,有點(diǎn)類似于CPU的中斷县钥;

用汽車和公路舉個例子:js公路只是單行道(主線程),但是有很多車道(輔助線程)都可以匯入車流(異步任務(wù)完成后回調(diào)進(jìn)入主線程的任務(wù)隊(duì)列)慈迈;generator把js公路變成了多車道(協(xié)程實(shí)現(xiàn))若贮,但是同一時間只有一個車道上的車能開(依然單線程),不過可以自由變道(移交控制權(quán))痒留;

三谴麦、async關(guān)鍵字

1)表明程序里面可能有異步過程

async關(guān)鍵字表明程序里面可能有異步過程,里面可以有await關(guān)鍵字伸头;當(dāng)然全部是同步代碼也沒關(guān)系匾效,但是這樣async關(guān)鍵字就顯得多余了;

2)非阻塞

async函數(shù)里面如果有異步過程會等待恤磷,但是async函數(shù)本身會馬上返回面哼,不會阻塞當(dāng)前線程,可以簡單認(rèn)為扫步,async函數(shù)工作在主線程魔策,同步執(zhí)行,不會阻塞界面渲染河胎,async函數(shù)內(nèi)部由await關(guān)鍵字修飾的異步過程闯袒,工作在相應(yīng)的協(xié)程上,會阻塞等待異步任務(wù)的完成再返回游岳;

3)async函數(shù)返回類型為Promise對象

這是和普通函數(shù)本質(zhì)上不同的地方政敢,也是使用時重點(diǎn)注意的地方;
(1)return newPromise();這個符合async函數(shù)本意胚迫;
(2)return data;這個是同步函數(shù)的寫法喷户,這里是要特別注意的,這個時候访锻,其實(shí)就相當(dāng)于Promise.resolve(data);還是一個Promise對象褪尝,但是在調(diào)用async函數(shù)的地方通過簡單的=是拿不到這個data的,因?yàn)榉祷刂凳且粋€Promise對象朗若,所以需要用.then(data => { })函數(shù)才可以拿到這個data恼五;
(3)如果沒有返回值昌罩,相當(dāng)于返回了Promise.resolve(undefined);

4)無等待

聯(lián)想到Promise的特點(diǎn)哭懈,在沒有await的情況下執(zhí)行async函數(shù),它會立即執(zhí)行茎用,返回一個Promise對象遣总,并且絕對不會阻塞后面的語句睬罗,這和普通返回Promise對象的函數(shù)并無二致;

5)await不處理異步error

await是不管異步過程的reject(error)消息的旭斥,async函數(shù)返回的這個Promise對象的catch函數(shù)負(fù)責(zé)統(tǒng)一抓取內(nèi)部所有異步過程的錯誤容达;async函數(shù)內(nèi)部只要有一個異步過程發(fā)生錯誤,整個執(zhí)行過程就中斷垂券,這個返回的Promise對象的catch就能抓取到這個錯誤花盐;

5)async函數(shù)的執(zhí)行

async函數(shù)執(zhí)行和普通函數(shù)一樣,函數(shù)名帶個()就可以了菇爪,參數(shù)個數(shù)隨意算芯,沒有限制,也需要有async關(guān)鍵字凳宙;只是返回值是一個Promise對象熙揍,可以用then函數(shù)得到返回值,用catch抓整個流程中發(fā)生的錯誤氏涩;

async function timeout(){
  return "hello world";
}
console.log(timeout());
console.log("誰先執(zhí)行呢届囚?");
/* Promise { 'hello world' }
誰先執(zhí)行呢? */
//async函數(shù)返回的是promise對象是尖,所以如果想調(diào)用輸出結(jié)果可以直接用then語句
timeout().then((res)=>{
  console.log(res);//hello world
})

四意系、await關(guān)鍵字

1)await只能在async函數(shù)內(nèi)部使用

不能放在普通函數(shù)里面,否則會報(bào)錯饺汹;

2)await關(guān)鍵字后面跟Promise對象

在Pending狀態(tài)時昔字,相應(yīng)的協(xié)程會交出控制權(quán),進(jìn)入等待狀態(tài)首繁,這是協(xié)程的本質(zhì)作郭;

3)await是async wait的意思

wait的是resolve(data)的消息,并把數(shù)據(jù)data返回弦疮,比如下面代碼中夹攒,當(dāng)Promise對象由Pending變?yōu)镽esolved的時候,變量a就等于data胁塞,然后再順序執(zhí)行下面的語句console.log(a)咏尝,這真的是等待,真的是順序執(zhí)行啸罢,表現(xiàn)和同步代碼幾乎一模一樣编检;

async function jianshu(data){
  const a=await new Promise((resolve,reject)=>{
    return resolve(data);
  });
  console.log(a);
}
jianshu("jianshu");//jianshu
4)await后面也可以跟同步代碼

不過系統(tǒng)會自動將其轉(zhuǎn)化成一個Promsie對象

const a = await 'hello world'
// 相當(dāng)于
const a = await Promise.resolve('hello world');
// 跟同步代碼是一樣的狭姨,還不如省事點(diǎn)撑碴,直接去掉await關(guān)鍵字
const a = 'hello world';
5)await對于失敗消息的處理
    await只關(guān)心異步過程成功的消息`resolve(data)`,拿到相應(yīng)的數(shù)據(jù)data叠国,至于失敗消息`reject(error)`衩匣,不關(guān)心不處理蕾总;對于錯誤的處理有以下幾種方法供選擇:
**讓await后面的Promise對象自己catch粥航;**
async function jianshu(data){
  const a=await new Promise((resolve,reject)=>{
    //resolve(data);
    reject("error");
  }).then((res)=>{
    return res;
  }).catch((err)=>{
    return err;
  })
  console.log(a);
}
jianshu("jianshu");//error
**也可以讓外面的async函數(shù)返回的Promise對象統(tǒng)一catch;**
function delay(num){
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      //resolve(num*2);
      reject("error");
    },200)
  })
}
async function test() {
  let a = await delay(3).then((res) => {
    return res;
  }).catch((err) => {
    return err;
  });
  console.log(a);
}
test();//error
**像同步代碼一樣生百,放在一個try...catch結(jié)構(gòu)中递雀;**
async function didMount() {
  // 將異步和同步的代碼放在一個try..catch中,異常都能抓到
  try {
    let array = null;
    let data = await asyncFunction();  
    if (array.length > 0) {  // 這里會拋出異常蚀浆,下面的catch也能抓到
      array.push(data);
    }
  } catch (error) {
    console.log(error);
  }
}
async function asyncFunction(){
  return 1;
}
didMount();//TypeError: Cannot read property 'length' of null
6)await對于結(jié)果的處理

await是個運(yùn)算符缀程,用于組成表達(dá)式,await表達(dá)式的運(yùn)算結(jié)果取決于它等的東西.

如果它等到的不是一個Promise對象市俊,那么await表達(dá)式的運(yùn)算結(jié)果就是它等到的東西杠输;

function delay(num){
  setTimeout(()=>{
    return num*2;
  },2000)
}
async function plus(){
  let a=await delay(3);
  /*這里await所等待的只是一個數(shù)值,因此不會阻塞后面的程序執(zhí)行秕衙,由于delay需要延時兩秒后才能執(zhí)行蠢甲,因此程序隔過await先執(zhí)行下面的輸出語句,又由于執(zhí)行輸出時a的值還沒有定義据忘,所以會輸出undefined*/
  console.log(a);
}
plus();//undefined

如果它等到的是一個Promise對象鹦牛,await就忙起來了,它會阻塞其后面的代碼勇吊,等著Promise對象resolve曼追,然后得到resolve的值,作為await表達(dá)式的運(yùn)算結(jié)果汉规;雖然是阻塞礼殊,但async函數(shù)調(diào)用并不會造成阻塞,它內(nèi)部所有的阻塞都被封裝在一個Promise對象中異步執(zhí)行针史,這也正是await必須用在async函數(shù)中的原因晶伦;

function delay(num){
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      resolve(num*2);
    },2000)
  })
}
async function plus(){
  let a=await delay(2);
  let b=await delay(3);
  let c=await delay(5);
  //這里await會阻塞后面程序的執(zhí)行,只有當(dāng)前面的三個await執(zhí)行完了之后才執(zhí)行后面的語句
  console.log(a+b+c);
}
plus();//20
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末啄枕,一起剝皮案震驚了整個濱河市婚陪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌频祝,老刑警劉巖泌参,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異常空,居然都是意外死亡沽一,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門漓糙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來铣缠,“玉大人,你說我怎么就攤上這事∪敛校” “怎么了拙友?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵为狸,是天一觀的道長歼郭。 經(jīng)常有香客問我,道長辐棒,這世上最難降的妖魔是什么病曾? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮漾根,結(jié)果婚禮上泰涂,老公的妹妹穿的比我還像新娘。我一直安慰自己辐怕,他們只是感情好逼蒙,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著寄疏,像睡著了一般是牢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上陕截,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天驳棱,我揣著相機(jī)與錄音,去河邊找鬼农曲。 笑死社搅,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的乳规。 我是一名探鬼主播形葬,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼暮的!你這毒婦竟也來了荷并?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤青扔,失蹤者是張志新(化名)和其女友劉穎源织,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體微猖,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡谈息,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了凛剥。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片侠仇。...
    茶點(diǎn)故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出逻炊,到底是詐尸還是另有隱情互亮,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布余素,位于F島的核電站豹休,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏桨吊。R本人自食惡果不足惜威根,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望视乐。 院中可真熱鬧洛搀,春花似錦、人聲如沸佑淀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽伸刃。三九已至谎砾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間奕枝,已是汗流浹背棺榔。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留隘道,地道東北人症歇。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像谭梗,于是被迫代替她去往敵國和親忘晤。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 一激捏、async/await的優(yōu)點(diǎn) 1)方便級聯(lián)調(diào)用:即調(diào)用依次發(fā)生的場景设塔; 2)同步代碼編寫方式: Promise...
    puxiaotaoc閱讀 105,612評論 7 62
  • 相對于回調(diào)函數(shù)來說,Promise是一種相對優(yōu)雅的選擇远舅。那么有沒有更好的方案呢闰蛔?答案就是async/await。優(yōu)...
    饑人谷_阿銀閱讀 857評論 0 0
  • 相對于回調(diào)函數(shù)來說图柏,Promise是一種相對優(yōu)雅的選擇序六。那么有沒有更好的方案呢?答案就是async/await蚤吹。優(yōu)...
    勇往直前888閱讀 47,255評論 8 36
  • 更詳細(xì)的解釋文章詳解轉(zhuǎn)載地址一例诀、async/await的優(yōu)點(diǎn)1)方便級聯(lián)調(diào)用:即調(diào)用依次發(fā)生的場景随抠;2)同步代碼編...
    Fanny閱讀 426評論 0 0
  • yield 協(xié)程里面重要的關(guān)鍵字yield,在生成的迭代器調(diào)用next繁涂,每次都會將yield后面的數(shù)據(jù)返回拱她,并中斷...
    落入糞池的鳳凰閱讀 1,207評論 0 3