Async/Await替代Promise的6個理由

Async/Await簡介

  • async/await是寫異步代碼的新方式躏尉,以前的方法有回調(diào)函數(shù)和Promise。
  • async/await是基于Promise實現(xiàn)的规阀,它不能用于普通的回調(diào)函數(shù)台汇。
  • async/await與Promise一樣,是非阻塞的啦撮。
  • async/await使得異步代碼看起來像同步代碼,這正是它的魔力所在汪厨。

Async/Await語法

Promise寫法:

const makeRequest = () =>
  getJSON()
    .then(data => {
      console.log(data)
      return "done"
    })
makeRequest()

Async/Await寫法:

const makeRequest = async () => {
  console.log(await getJSON())
  return "done"
}
makeRequest()

示例中赃春,getJSON函數(shù)返回一個promise,這個promise成功resolve時會返回一個promise對象劫乱。我們只是調(diào)用這個函數(shù)织中,打印返回的JSON對象,然后返回“done”衷戈。

它們有一些細微不同:

  • 函數(shù)前面多了一個async關(guān)鍵字狭吼。await關(guān)鍵字只能用在async定義的函數(shù)內(nèi)。async函數(shù)會隱式的返回一個promise殖妇,該promise的resolve值就是函數(shù)return的值刁笙。(示例中resolve值就是字符串"done")
  • 第1點暗示我們不能在最外層代碼中使用await,因為不在async函數(shù)內(nèi)谦趣。
//不能在最外層代碼中使用await
await makeRequest()

//這是會出事的
makeRequest().then((result) => {
  //代碼
})

await getJSON()表示console.log會等到getJSON的promise成功reosolve之后再執(zhí)行疲吸。

為什么Async/Await更好?

1. 簡潔

由示例可知前鹅,使用Async/Await明顯節(jié)約了不少代碼摘悴。我們不需要寫.then,不需要寫匿名函數(shù)處理Promise的resolve值舰绘,也不需要定義多余的data變量蹂喻,還避免了嵌套代碼。這些小的優(yōu)點會迅速累計起來捂寿,這在之后的代碼示例中會更加明顯口四。

2. 錯誤處理

Async/Await讓try/catch可以同時處理同步和異步錯誤。在下面的promise示例中者蠕,try/catch不能處理JSON.parse的錯誤窃祝,因為它在Promise中。我們需要使用.catch踱侣,這樣錯誤處理代碼非常冗余粪小。并且,在我們的實際生產(chǎn)代碼會更加復雜抡句。

const makeRequest = () => {
  try {
    getJSON()
      .then(result => {
        // JSON.parse可能會出錯
        const data = JSON.parse(result)
        console.log(data)
      })
      // 取消注釋探膊,處理異步代碼的錯誤
      // .catch((err) => {
      //   console.log(err)
      // })
  } catch (err) {
    console.log(err)
  }
}

使用aync/await的話,catch能處理JSON.parse錯誤:

const makeRequest = async () => {
  try {
    // this parse may fail
    const data = JSON.parse(await getJSON())
    console.log(data)
  } catch (err) {
    console.log(err)
  }
}

3. 條件語句

下面示例中待榔,需要獲取數(shù)據(jù)逞壁,然后根據(jù)返回數(shù)據(jù)決定是直接返回,還是繼續(xù)獲取更多的數(shù)據(jù)锐锣。

const makeRequest = () => {
  return getJSON()
    .then(data => {
      if (data.needsAnotherRequest) {
        return makeAnotherRequest(data)
          .then(moreData => {
            console.log(moreData)
            return moreData
          })
      } else {
        console.log(data)
        return data
      }
    })
}

上面的代碼嵌套(6層)腌闯、括號、return語句很容易讓人看不懂雕憔。

使用Async/Await編寫:

const makeRequest = async () => {
  const data = await getJSON()
  if (data.needsAnotherRequest) {
    const moreData = await makeAnotherRequest(data);
    console.log(moreData)
    return moreData
  } else {
    console.log(data)
    return data    
  }
}

4. 中間值

你可能遇到過這樣的場景姿骏,調(diào)用promise1,使用promise1返回的結(jié)果調(diào)用promise2斤彼,然后使用兩者的結(jié)果調(diào)用promise3分瘦。使用promise的代碼是:

const makeRequest = () => {
  return promise1()
    .then(value1 => {
      return promise2(value1)
        .then(value2 => {        
          return promise3(value1, value2)
        })
    })
}

如何promise3不使用value1,可以很簡單的將promise鋪平琉苇。如果忍受不了嵌套嘲玫,可以將value1 & value2放進Promise.all來避免深層嵌套:

const makeRequest = () => {
  return promise1()
    .then(value1 => {
      return Promise.all([value1, promise2(value1)])
    })
    .then(([value1, value2]) => {      
      return promise3(value1, value2)
    })
}

這種方法為了可讀性犧牲了語義,除了避免嵌套并扇,并沒有其他理由將value1和value2放在一個數(shù)組中去团。

使用async/await的話,代碼會變得異常簡單和直觀:

const makeRequest = async () => {
  const value1 = await promise1()
  const value2 = await promise2(value1)
  return promise3(value1, value2)
}

5. 錯誤棧

const makeRequest = () => {
  return callAPromise()
    .then(() => callAPromise())
    .then(() => callAPromise())
    .then(() => callAPromise())
    .then(() => callAPromise())
    .then(() => {
      throw new Error("oops");
    })
}
makeRequest()
  .catch(err => {
    console.log(err);
    // output
    // Error: oops at callAPromise.then.then.then.then.then (index.js:8:13)
  })

上述示例中調(diào)用了多個promise穷蛹,假設(shè)promise鏈中某個地方拋出了一個異常渗勘,返回的錯誤棧沒有給出錯誤發(fā)生的位置信息。

async/await中的錯誤棧會指向錯誤所在的函數(shù):

const makeRequest = async () => {
  await callAPromise()
  await callAPromise()
  await callAPromise()
  await callAPromise()
  await callAPromise()
  throw new Error("oops");
}
makeRequest()
  .catch(err => {
    console.log(err);
    // output
    // Error: oops at makeRequest (index.js:7:9)
  })

在開發(fā)過程中俩莽,可能這一點優(yōu)勢并不是很大旺坠。但是,如果是分析生產(chǎn)環(huán)境的錯誤日志時扮超,它將非常有用取刃。

6. 調(diào)試

async/await能夠使代碼更方便調(diào)試。
promise調(diào)試非常痛苦:

  • 不能在返回表達式的箭頭函數(shù)中設(shè)置斷點
const makeRequest = () => {
    return callAPromise()
      .then(() => callAPromise())
      .then(() => callAPromise())
      .then(() => callAPromise())
      .then(() => callAPromise())
}
  • 如果在.then代碼塊中設(shè)置斷點出刷,使用Step Over快捷鍵璧疗,調(diào)試器不會調(diào)到下一個.then,因為它只會跳過異步代碼馁龟。

使用async/await時崩侠,不再需要那么多箭頭函數(shù),這樣就可以像調(diào)試同步代碼一樣跳過await語句坷檩。

const makeRequest = async () => {
    await callAPromise()
    await callAPromise()
    await callAPromise()
    await callAPromise()
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末却音,一起剝皮案震驚了整個濱河市改抡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌系瓢,老刑警劉巖阿纤,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異夷陋,居然都是意外死亡欠拾,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門骗绕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來藐窄,“玉大人,你說我怎么就攤上這事酬土【H蹋” “怎么了?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵诺凡,是天一觀的道長东揣。 經(jīng)常有香客問我,道長腹泌,這世上最難降的妖魔是什么嘶卧? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮凉袱,結(jié)果婚禮上芥吟,老公的妹妹穿的比我還像新娘。我一直安慰自己专甩,他們只是感情好钟鸵,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著涤躲,像睡著了一般棺耍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上种樱,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天蒙袍,我揣著相機與錄音,去河邊找鬼嫩挤。 笑死害幅,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的岂昭。 我是一名探鬼主播以现,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了邑遏?” 一聲冷哼從身側(cè)響起佣赖,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎无宿,沒想到半個月后茵汰,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體枢里,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡孽鸡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了栏豺。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片彬碱。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖奥洼,靈堂內(nèi)的尸體忽然破棺而出巷疼,到底是詐尸還是另有隱情,我是刑警寧澤灵奖,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布嚼沿,位于F島的核電站,受9級特大地震影響瓷患,放射性物質(zhì)發(fā)生泄漏骡尽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一擅编、第九天 我趴在偏房一處隱蔽的房頂上張望攀细。 院中可真熱鬧,春花似錦爱态、人聲如沸谭贪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽俭识。三九已至,卻和暖如春洞渔,著一層夾襖步出監(jiān)牢的瞬間套媚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工痘煤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留凑阶,地道東北人。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓衷快,卻偏偏與公主長得像宙橱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359

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