乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      JavaScript異步之從promise到await

       Coder編程 2020-02-24

      一、從回調到Promise,為什么要使用它

      當我們在執(zhí)行異步任務的時候,往往會使用一個回調函數,它會在異步任務結束時被調用,它有一個共同點就是會在未來被執(zhí)行。例如在node.js中異步讀取文件:

      fs.readFile('/etc/passwd', (err, data) => {
        if (err) throw err;
        console.log(data);
      });

      又如我們寫了個ajax請求函數:

      // 簡化版,請忽略細節(jié)
      const request = function(callback){
        let xhr = new XMLHttpRequest();
         // .....
        xhr.onreadystatechange = function(){
          callback(xhr)              
        }
      }
      //調用
      request(function(xhr){
        if (xhr.readyState === 4 && xhr.status === 200) {
            // ....
        } else {
            //....
        }  
      })
      

      甚至是一個定時器任務:

      const doSomethingLater = function(delay, callback){
          setTimeout(callback, delay*1000)
      }
      // 調用
      doSomethingLater(1, function(){
        // .....
      })

      這樣看使用回調的方式似乎沒什么問題,但是當回調函數中又有異步任務時,就可能出現多層回調,也就是回調地獄的問題。多層回調降低了代碼的可讀性和可維護性。

      Promise為我們做了什么

      簡單來講,Promise將異步任務包裝成對象,將異步任務完成后要執(zhí)行的函數傳給then方法,通過resolve來調用該函數。如上面定時器任務可以改寫成:

      const doSomethingLater = function(delay){
          return new Promise((resolve)=>{
            setTimeout(()=>{ resolve() }, delay*1000)
          })
      }
      doSomethingLater(1)
          .then(()=>{
            console.log('任務1')
          })

      如果定時任務中又執(zhí)行定時任務,就可以這樣寫,而不是再嵌套一層回調:

      doSomethingLater(1)
          .then(() => {
              console.log('任務1')
              return doSomethingLater(1)
          })
          .then(() => {
              console.log('任務2')
          })

      Promise的作用:

      • 把異步任務完成后的處理函數換個位置放:傳給then方法,并支持鏈式調用,避免層層回調。
      • 捕獲錯誤:不管是代碼錯誤還是手動reject(),都可以用一個函數來處理這些錯誤。

      二、你可能不知道的Promise細節(jié)

      用了Promise就是異步代碼

      就算你的代碼原來沒有異步操作:

      Promise.resolve()
          .then(() => {
              console.log(1)
          })
      console.log(2)
      // 2
      // 1

      這一點可以查一下事件循環(huán)相關知識

      catch的另一種寫法
      Promise.reject('error')
          .then(() => {
          })
          .catch((err) => {
              console.log(err)
          })
      // 等價于
      Promise.reject('error')
          .then(() => {
          })
          .then(null, (err) => {
              console.log(err)
          })
      // 或者
      Promise.reject('error')
          .then(() => {
          }, (err) => {
              console.log(err)
          })

      其實catch只是個語義化的語法糖,我們也可以直接用then來處理錯誤。

      then 或 catch 方法始終返回promise對象

      then方法第一個參數和第二個參數(或catch的參數),只是調用條件不同。

      Promise.resolve()
          .then(() => {
              return 1
          })
          .then((res) => {
              console.log(res) // 1
          })
          
      Promise.resolve()
          .then(() => {
             // 不返回什么
          })
          .then((res) => {
              console.log(res) // undefined,因為函數默認返回undefined 
          })
         

      如果是返回一個promise對象:

      Promise.resolve()
          .then(() => {
              return new Promise((resolve) => {
                  resolve(2)
              })
          })
          .then((res) => {
              console.log(res) // 2, 根據返回的那個promise對象的狀態(tài)來
          })

      我們可以通過包裝,使一個promise對象的最后狀態(tài)始終是成功的:
      例如:

      const task = () => {
          return new Promise((resolve, reject) => {
              // ....
          })
      }
      task()
          .then((res) => {
              console.log(res)
          })
          .catch((err) => {
              console.log(err)
          })

      原本調用task函數時需要在外面加一層catch捕獲錯誤,其實可以包裝一下:

      const task = () => {
          return new Promise((resolve, reject) => {
              // ....
          })
              .then((res) => {
                  return {
                      status: 'success',
                      value: res
                  }
              })
              .catch((err) => {
                  return {
                      status: 'fail',
                      value: err
                  }
              })
      }
      // 現在調用就會更簡潔!
      task()
          .then((result) => {
              console.log(result)
          })
      

      catch中報錯也可以在后面繼續(xù)捕獲,因為catch也是返回promise對象嘛

      Promise.reject('first error')
          .catch((err) => {
              console.log(err)
              throw new Error('second error')
          })
          .then(null, (err) => {
              console.log(err)
          })

      三、await:新的語法糖

      await使得異步代碼更像是同步代碼,對串行的異步調用寫起來更自然。await后面跟一個值或promise對象,如果是一個值,那么直接返回。如果是一個promise對象,則接受promise對象成功后的返回值?;蛘咴赼wait后面調用一個async函數

      const task = async () => {
          return new Promise((resolve, reject) => {
              resolve(1)
          })
      }
      const handle = async () => {
          let value = await task()
          console.log(value)
      }
      handle() // 1

      使用await要注意錯誤的捕獲,因為await只關心成功

      const task = async () => {
          return new Promise((resolve, reject) => {
              reject(1)
          })
      }
      const handle = async () => {
          let value = await task()
          console.log(value)
      }
      handle()

      這樣寫會報錯,所以要么在task函數中捕獲錯誤,要么就在task調用時捕獲,像這樣:

      const task = async () => {
          return new Promise((resolve, reject) => {
              reject(1)
          })
      }
      const handle = async () => {
          let value = await task().catch((err) => { console.log(err) })
          console.log(value) // undefine, 因為錯誤處理函數沒返回值,你也可以返回錯誤信息,這樣就會通過value拿到
      }

      需要注意的是,使用await也會使代碼變成異步的:

      const handle = async () => {
          let value = await 1
          console.log(value)
      }
      handle()
      console.log(2)
      // 2
      // 1

      完~

        本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯系方式、誘導購買等信息,謹防詐騙。如發(fā)現有害或侵權內容,請點擊一鍵舉報。
        轉藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多