淺談js中的回調地獄問題

淺談js中的回調地獄問題

  • 什麼是回調地獄

    • 說起回調地獄 首先想到的是異步 在js中我們經常會大量使用異步回調,例如使用ajax請求
      我們來看下面這段代碼:
      function a(functionb(){
          c(function d(){
          
          })
      })
      
      我們發現上面代碼大量使用了回調函數(將一個函數作爲參數傳遞給另個函數)並且有許多 })結尾的符號,使得代碼看起來很混亂。
  • 如何解決回調地獄呢

    • 第一種使用ES6中的Promise,中文翻譯過來承諾,意思是在未來某一個時間點承諾返回數據給你。

    • Promise有三種狀態:pending/reslove/reject 。pending就是未決,resolve可以理解爲成功,reject可以理解爲拒絕。
    • 同時Promise常用的三種方法 then 表示異步成功執行後的數據狀態變爲reslove catch 表示異步失敗後執行的數據狀態變爲reject all表示把多個沒有關係的Promise封裝成一個Promise對象使用then返回一個數組數據。
    • 下面一起來看看如何使用Promise:
      function f() {
            let promise = new Promise((resolve, reject) => {
                //模擬異步
                setTimeout(()=>{
                   resolve('prom')
                },1000)
        
            })
            return promise;
        }
      
      Promise 構造函數有兩個變量 resolve 用於返回異步執行成功的函數 reject 用於返回異步執行失敗的函數。配合then與catch一起使用
    • 使用then獲取數據
       function f1() {
       //返回一個Promise用於下一次調用then
           return f().then(data=>{
           // 返回的數據用於下一次then使用
               return data+'ise'
           })
       }
      
      使用then方法 獲取到上一步resolve返回的數據
    • 獲取數據
       f1().then(data=>{
           console.log(data)
       })
       console.log("hello word")	
      
      如果猜的不錯輸出應該爲promise在這裏插入圖片描述
      輸出了promise 說明上面是正確的,並且先輸出 hello word 後輸出promise 說明Promise是異步執行的
  • 但是如果過多的使用then 也會照成新的執行流程問題。所以我們的另一位主角登場了,那就是ES6中的Generator(生成器)

    • Generator(生成器)是一種有效利用內存的機制,一邊循環一邊計算生成數值的機制。通過配合Promise可以更加優雅的寫異步代碼
    • 下面我們來試試:
      function f1() {
           let promise = new Promise((resolve, reject) => {
               setTimeout(function () {
                   resolve("hello word")
               })
           })
           return promise;
       } 
      
      首先我們先用Promise分裝一個異步請求模擬ajax。
    • 構建一個生成器函數
         function *f() {
            let x = yield f1();
            console.log("ni hao")
        }	
      
      構建生成器非常簡單 只需要在函數方法名前面加一個 * 這個函數就是一個生成器函數,可能有人注意到函數體中有一個yield關鍵字(學過python應該知道),簡單點說yield類似return 也是返回值的,區別在於當程序 執行到yield後會返回yield後面的表達式,並且程序暫停在這裏保存當前值狀態,程序只是暫停在這裏並沒有中止。
    • 獲取生成器的值
          var it = f();
          it.next().value.then(data=>{
         console.log(data)
        })
        console.log(123)
        it.next()
        console.log(it.next())
      
      使用next()方法可以獲取到yield第一次暫停的值返回的是{ value: 值 done: true } value表示yield返回的值,done表示是否迭代完畢。當然也可以使用netx(10)來給yield設置下次執行的值。
    • 輸出結果
      在這裏插入圖片描述
      通過結果我們看到生成器也是異步執行。
  • 當然生成器不是最完美的,它的語法讓人難以理解,所以ES7推出了async/await (異步等待),多麼貼切。

    • 封裝異步請求
         function f() {
            return new Promise((resolve, reject) => {
                 setTimeout(()=>{
                   resolve("hello word")
                 },1000)
              })
         }
      
      上面講過了這裏不再贅述。
    • 使用異步函數
      async function a(){
         var data = await f();
         return data;
      }
      
      函數前面加async 表示該函數是一個異步函數 await 表示等待一個異步值的到來,
    • 獲取值
      var a = a()
       a.then(data=>{
           console.log(data)
       })
      
      異步函數返回的是一個Promise對象,到這裏是不是豁然開朗了,return返回的值通過使用then來進行獲取,到這裏有人會問這個不是和生成器一樣嗎只是把* 換成async ,yield緩存await 嗎? 沒錯確實一樣,但是生成器返回的是一個迭代器,而 異步函數返回的是一個Promise,異步函數可以以更加方便的同Promise結合使用來書寫同步代碼風格的異步執行。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章