1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        明明有了 promise ,為啥還需要 async await ?

        共 8712字,需瀏覽 18分鐘

         ·

        2021-06-24 08:14

        推薦關(guān)注↓

        點擊上方 程序員成長指北,關(guān)注公眾號

        回復1,加入高級Node交流群


        為了讓還沒聽說過這個特性的小伙伴們有一個大致了解,以下是一些關(guān)于該特性的簡要介紹:

        async/await是一種編寫異步代碼的新方法。在這之前編寫異步代碼使用的是回調(diào)函數(shù)和promise。
        async/await實際是建立在promise之上的。因此你不能把它和回調(diào)函數(shù)搭配使用。
        async/await可以使異步代碼在形式上更接近于同步代碼。這就是它最大的價值。

        語法

        假設(shè)有一個getJSON方法,它返回一個promise,該promise會被resolve為一個JSON對象。我們想要調(diào)用該方法,輸出得到的JSON對象,最后返回"done"。

        以下是使用promise的實現(xiàn)方式:

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

        使用async/await則是這樣的:

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

        makeRequest()

        使用async/await時有以下幾個區(qū)別:

        在定義函數(shù)時我們使用了async關(guān)鍵字。await關(guān)鍵字只能在使用async定義的函數(shù)的內(nèi)部使用。所有async函數(shù)都會返回一個promise,該promise最終resolve的值就是你在函數(shù)中return的內(nèi)容。
        由于第一點中的原因,你不能在頂級作用域中await一個函數(shù)。因為頂級作用域不是一個async方法。

        // this will not work in top level
        // await makeRequest()
            
        // this will work
        makeRequest().then((result) => {
          // do something
        })

        await getJSON()意味著直到getJSON()返回的promise在resolve之后,console.log才會執(zhí)行并輸出resolove的值。

        為何使用async/await編寫出來的代碼更好呢?

        1. 簡潔

        看看我們節(jié)省了多少代碼吧。即使是在這么一個簡單的例子中,我們也節(jié)省了可觀的代碼。我們不需要為.then編寫一個匿名函數(shù)來處理返回結(jié)果,也不需要創(chuàng)建一個data變量來保存我們實際用不到的值。我們還避免了代碼嵌套。這些小優(yōu)點會在真實項目中變得更加明顯。

        2. 錯誤處理

        async/await終于使得用同一種構(gòu)造(古老而好用的try/catch) 處理同步和異步錯誤成為可能。在下面這段使用promise的代碼中,try/catch不能捕獲JSON.parse拋出的異常,因為該操作是在promise中進行的。要處理JSON.parse拋出的異常,你需要在promise上調(diào)用.catch并重復一遍異常處理的邏輯。通常在生產(chǎn)環(huán)境中異常處理邏輯都遠比console.log要復雜,因此這會導致大量的冗余代碼。

        const makeRequest = () => {
            try {
            getJSON()
              .then(result => {
                // this parse may fail
                const data = JSON.parse(result)
                console.log(data)
              })
              // uncomment this block to handle asynchronous errors
              // .catch((err) => {
              //   console.log(err)
              // })
            } catch (err) {
                console.log(err)
            }
        }

        現(xiàn)在看看使用了async/await的情況,catch代碼塊現(xiàn)在可以捕獲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è)有如下邏輯的代碼。請求數(shù)據(jù),然后根據(jù)返回數(shù)據(jù)中的某些內(nèi)容決定是直接返回這些數(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
              }
            })
        }

        只是閱讀這些代碼已經(jīng)夠讓你頭疼的了。一不小心你就會迷失在這些嵌套(6層),空格,返回語句中。(當然我們一般用請求數(shù)據(jù)的返回值作為判斷條件不會寫成這樣,也許我這個小白會...) 在使用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. 中間值

        比如你向一個url1發(fā)送請求,拿到返回值1,然后用這個返回值1當作參數(shù)去請求url2,拿到返回值2,然后拿返回值1和返回值2作為參數(shù)去請求url3,拿到最終的返回結(jié)果。
        對應的代碼看起來是這樣的:

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

        如果promise3沒有用到value1,那么我們就可以把這幾個promise改成嵌套的模式。如果你不喜歡這種編碼方式,你也可以把value1和value2封裝在一個Promsie.all調(diào)用中以避免深層次的嵌套:

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

        這種方式為了保證可讀性而犧牲了語義。除了避免嵌套的promise,沒有其它理由要把value1和value2放到一個數(shù)組里。

        同樣的邏輯如果換用async/await編寫就會非常簡單,直觀。

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

        5. 異常堆棧

        假設(shè)有一段串行調(diào)用多個promise的代碼,在promise串中的某一點拋出了異常:

        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)
          })

        從promise串返回的異常堆棧中沒有包含關(guān)于異常是從哪一個環(huán)節(jié)拋出的信息。更糟糕的是,它還會誤導你,它包含的唯一的函數(shù)名是callAPromise,然而該函數(shù)與此異常并無關(guān)系。(這種情況下文件名和行號還是有參考價值的)。

        然而,在使用了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ā)環(huán)境中可能并不明顯,但當你想要在生產(chǎn)環(huán)境的服務器上獲取有意義的異常信息時,這會非常有用。在這種情況下,知道異常來自makeRequest而不是一連串的then調(diào)用會有意義的多。

        6. 調(diào)試

        最后壓軸的一點,使用async/await最大的優(yōu)勢在于它很容易被調(diào)試。由于以下兩個原因,調(diào)試promise一直以來都是很痛苦的。

        你不能在一個返回表達式的箭頭函數(shù)中設(shè)置斷點(因為沒有代碼塊)


        如果你在一個.then代碼塊中使用調(diào)試器的步進(step-over)功能,調(diào)試器并不會進入后續(xù)的.then代碼塊,因為調(diào)試器只能跟蹤同步代碼的『每一步』。

        通過使用async/await,你不必再使用箭頭函數(shù)。你可以對await語句執(zhí)行步進操作,就好像他們都是普通的同步調(diào)用一樣。


        結(jié)論 async/await是過去幾年中JavaScript引入的最具革命性的特性之一。它使你意識到promise在語法上的糟糕之處,并提供了一種簡單,直接的替代方案。

        參考文章

        https://loveky.github.io/2017/04/09/translte-6-reasons-why-javascripts-async-await-blows-promises-away/


        轉(zhuǎn)自:Angus安格斯

        https://juejin.cn/post/6960855679208783903

        最后

        如果覺得這篇文章還不錯
        點擊下面卡片關(guān)注我
        來個【分享、點贊、在看】三連支持一下吧

           “分享、點贊、在看” 支持一波 

        瀏覽 32
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            欧美一级毛片久久99精品蜜桃 | 黄色小电影在线 | 国精产品一区二区三区黑人和中国 | 国产成人精品午夜福利A蜜臀 | 7777777亚洲 | 91级片| 操逼一区二区三区 | 婷婷五月深爱激情 | 亚洲v欧美v日韩v国产v在线 | 大鸡巴A片 |