Promise介紹及jQuery deferred詳解

callback.png
Promise介紹

Promise 是 JavaScript 的異步操作解決方案,是ES6提出的異步操作解決方案之一。
其為異步操作提供統(tǒng)一接口。它起到代理作用(proxy),充當(dāng)異步操作與回調(diào)函數(shù)之間的中介,使得異步操作具備同步操作的接口。Promise 可以讓異步操作寫起來,就像在寫同步操作的流程,而不必一層層地嵌套回調(diào)函數(shù)。

為什么會有promise?
其實在jquery很早以前就有了十分類似promise的方案,該方案的出現(xiàn)是為了解決回調(diào)地獄以及傳統(tǒng)回調(diào)寫法不太符合開放封閉的設(shè)計原則而產(chǎn)生的,Promise的出現(xiàn)很好地實現(xiàn)了對擴(kuò)展開放,對修改封閉的原則,可拓展性和可讀性較高。
傳統(tǒng)的回調(diào)寫法

step1(function (value1) {
  step2(value1, function(value2) {
    step3(value2, function(value3) {
      step4(value3, function(value4) {
        // ...
      });
    });
  });
});
jQuery異步操作歷史

jQuery 1.5版本之前
提出的異步解決方案,以ajax為主:

var ajax = $.ajax({
            url: './data.json',
            success: function () {
                console.log('success 1')
                console.log('success 2')
                console.log('success 3')
            },
            error: function () {
                console.log('error')
            }
        })
console.log(ajax) //返回的是一個XHR對象

jQuery 1.5版本
引入deferred對象,deferred英文是延期的意思

   var ajax = $.ajax('./data.json')
        ajax.done(function () {
            console.log('success a')
        }).fail(function () {
            console.log('fail 1')
        }).done(function () {
            console.log('success b')
        }).fail(function () {
            console.log('fail 2')
        }).done(function () {
            console.log('success c')
        }).fail(function () {
            console.log('fail 3')
        })
        console.log(ajax) //返回一個deferred對象

jQuery 1.5版本之后
使用了then關(guān)鍵字,此時,我們可以看到,已經(jīng)和Promise的寫法很像了。

  var ajax = $.ajax('./data.json')
        ajax.then(function () {
            console.log('success 100')
        }, function () {
            console.log('fail 100')
        }).then(function () {
            console.log('success 200')
        }, function () {
            console.log('fail 200')
        }).then(function () {
            console.log('success 300')
        }, function () {
            conso3le.log('fail 00')
        })

jQuery Deferred的使用
首先,我們看下未使用deferred的情況

        var wait = function () {
            var task = function () {
                console.log('執(zhí)行完成')
            }
            setTimeout(task, 2000)
        }
        wait()

引入deferred后可以使用promise的寫法,傳入dtd, 成功執(zhí)行resolve, 失敗執(zhí)行reject

      function waitHandle() {
            // 定義
            var dtd = $.Deferred() // 創(chuàng)建一個deferred對象
            var wait = function (dtd) {
                var task = function () {
                    console.log('執(zhí)行完成')
                    // 成功
                    dtd.resolve()
                    // 失敗
                    // dtd.reject()
                }
                setTimeout(task, 1000)
                // wait 返回
                // return dtd 1.5之前返回deferred對象
                return dtd.promise() // 1.5之后返回promise
            }
            // 最終返回
            return wait(dtd)
        }

deferred的實際使用及API分類
API分類
第一類:dtd.resolve, dtd.reject
第二類:dtd.then, dtd.done, dtd.fail
兩者不能混用, then是被動監(jiān)聽執(zhí)行,resolve等是主動執(zhí)行

  var w = waitHandle()  // promise 對象
//以下是1.5之前的寫法,返回的是deferred對象
/*w.then(function () {
            console.log('ok 1')
        }, function () {
            console.log('err 1')
        })
*/
//以下是1.5之后的jquery promise寫法,使用者不能直接使用主動調(diào)用的w.reject, w.resolve方法
        $.when(w).then(function () {
            console.log('ok 1')
        }, function () {
            console.log('err 1')
        })

Promise

Promise標(biāo)準(zhǔn)
promise可以看作一種狀態(tài)管理

  • 總共有三種狀態(tài) pending, fulfilled, rejected
  • 初始狀態(tài)是pending
  • pending可以變?yōu)閒ulfilled或pending之一
  • 狀態(tài)變化不可逆

promise必須實現(xiàn)then方法

  • then()必須可以接收兩個函數(shù)作為參數(shù)
  • then()返回的必須是一個promise實例

then 方法可以接受兩個回調(diào)函數(shù),第一個是異步操作成功時(變?yōu)閒ulfilled狀態(tài))時的回調(diào)函數(shù),第二個是異步操作失?。ㄗ?yōu)閞ejected)時的回調(diào)函數(shù)(該參數(shù)可以省略)。一旦狀態(tài)改變,就調(diào)用相應(yīng)的回調(diào)函數(shù)。then對上一步的結(jié)果負(fù)責(zé),then中的resolve在上一步resolve和reject都成功時執(zhí)行,reject在上一步resolve和reject任意一個失敗時執(zhí)行,可以進(jìn)行鏈?zhǔn)秸{(diào)用

Promise解決了什么問題?
使用Promise其實并沒有改變JS異步和單線程的本質(zhì),只是從寫法上杜絕了callback這種形式。Promise是一種語法糖,其解構(gòu)了代碼,更好地符合了開放封閉原則。
一般現(xiàn)代瀏覽器都支持了Promise,若不支持可以使用bluebird插件

Promise的寫法

      function loadImg(src) {
            var promise = new Promise(function (resolve, reject) {
                var img = document.createElement('img')
                img.onload = function () {
                    resolve(img)
                }
                img.onerror = function () {
                    reject('圖片加載失敗')
                }
                img.src = src
            })
            return promise
        }

Promise的異常捕獲
promise.then最后加上.catch,可以統(tǒng)一捕獲throw的系統(tǒng)錯誤以及reject中的信息

   var result = loadImg(src)
        result.then(function (img) {
            console.log(1, img.width)
            return img
        }).then(function (img) {
            console.log(2, img.height)
        }).catch(function (ex) {
            // 統(tǒng)一捕獲異常
            console.log(ex)
        })

Promise其他api, all與race
all需要傳入多個promise實例,全部實例完成后再繼續(xù),而race只需其中一個完成即可繼續(xù)

Promise_all_race.png

async await

promise中的then只是將callback進(jìn)行了拆分。
更進(jìn)一步可以使用asyn 結(jié)合await使用同步的方式寫異步的callback. 其是對promise的進(jìn)一步封裝,對寫法上的封裝。改變不了JS單線程、異步的本質(zhì)

  • 使用方法
    在return promise對象的函數(shù)前加await
    可以獲取promise執(zhí)行后的結(jié)果,而不是返回promise對象
const load = async function() {
  const result1 = await loadImg(src1)
  console.log(result1)
   const result2 = await loadImg(src2)
    console.log(result2)  
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容