範例解析ES6 Promise的原理和使用

2022-08-09 18:04:25

1. Promise 之前

1.1 回撥函數

回撥函數:把函數A當作引數傳遞給另一個函數B呼叫,那麼A就是回撥函數。【推薦:】

一些例子
具名回撥

function 你有幾隻狗(fn){
    fn('一隻狗')
}function 數狗(數量){
    console.log(數量)
}
你有幾隻狗(數狗)   // 一隻狗

匿名回撥

function 你有幾隻狗(fn){
    fn('一隻狗')
}
你有幾隻狗(function(數量){console.log(數量) 
})         //  一隻狗

常見的例子
jQuery中使用回撥函數,這裡用的是匿名回撥的方式

$("#btn").click(function(){
    console.log('點到我了')
})

1.2 回撥地獄(回撥缺點1)

回撥地獄:指的是回撥巢狀過多的情況,導致程式碼很難被看懂。

let info = []function 你有幾隻狗(fn){
    fn('一隻狗')
}function 你有幾隻貓(fn){
    fn('一隻貓')
}function 知道了(數量,callback){
    info.push(數量)
    console.log(info)    if(callback){
        callback()
    }
}// 開始呼叫 如果比這再多幾層,就不容易看懂了你有幾隻狗(function(狗數){
    console.log(狗數)
    知道了(狗數, function(){
        你有幾隻貓(function(貓數){
            console.log(貓數)
            知道了(貓數)
        })
    })
})

1.3 不使用Promise,如何解決

利用具名函數代替匿名函數

let info = []function 你有幾隻狗(fn){
    fn('一隻狗')
}function 你有幾隻貓(fn){
    fn('一隻貓')
}function 知道了(數量,callback){
    info.push(數量)
    console.log(info)    if(callback){
        callback()
    }
}function 告訴你貓的個數(貓數){
    console.log(貓數)
    知道了(貓數)
}function 繼續數(){
    你有幾隻貓(告訴你貓的個數)
}function 告訴你狗的個數(狗數){
    console.log(狗數)
    知道了(狗數, 繼續數)
}
你有幾隻狗(告訴你狗的個數)  // 好像也沒好到哪去。。。

1.4 回撥方式各不相同,需要單獨記憶(回撥缺點2)

readFile('C:\\1.txt',function (error, data) {   // node.js 讀取檔案方法中的回撥
        if(error) {
            console.log('成功')
            console.log(data.toString())
        } else {
            console.log('讀取檔案失敗')
        }
    })

$.ajax({                              // jQuery中ajax方法中的回撥
    url:'/2.txt'
    success: function(response) {
        console.log('成功')
    },
    error: function(){
        console.log('失敗')
    }
})

2. Promise 的目的

Promise 是非同步程式設計的一種解決方案,比傳統的解決方案——回撥函數和事件——更合理和更強大。它由社群最早提出和實現,ES6 將其寫進了語言標準,統一了用法,原生提供了Promise物件。

3. Promise 的原理

3.1 實現原理

ES6 規定,Promise物件是一個建構函式,用來生成Promise範例。通過在函數內部return 一個 Promise物件的範例,這樣就可以使用Promise的屬性和方法進行下一步操作了。

function 函數名(){    return new Promise(function(resolve, reject) {
        // ... some code          if (/* 非同步操作成功 */){
            resolve(value);   // 非同步操作成功時呼叫,把結果作為引數傳遞出去
          } else {
            reject(error);     // 非同步失敗時呼叫,把錯誤作為引數傳遞出去
          }

    })
}

3.2 呼叫邏輯

3.2.png
S1和E1兩個都沒有報錯,執行S2(resolve執行,系統認為搞定了,沒報錯)
S1和E1任何一個有報錯,執行E2(reject執行,系統認為沒搞定,報錯了)

4. Promise 的使用

4.1 Promise 的屬性與方法

屬性
Promise.prototype 表示 Promise 構造器的原型
方法
Promise.prototype.then()
返回一個 Promise 。它最多需要有兩個引數:Promise 的成功和失敗情況的回撥函數。
Promise.prototype.catch()
返回一個Promise,並且處理拒絕的情況。等價於Promise.prototype.then(undefined, onRejected)
Promise.prototype.finally()
finally() 方法返回一個Promise,在執行then()和catch()後,都會執行finally指定的回撥函數。避免同樣的語句需要在then()和catch()中各寫一次的情況。
Promise.all(iterable)
返回一個 Promise 範例,iterable引數內所有的 promise 都resolved後,才回撥完成resolve。
Promise.race(iterable)
返回一個 promise ,並伴隨著 promise物件解決的返回值或拒絕的錯誤原因, 只要 iterable 中有一個 promise 物件」解決(resolve)」或」拒絕(reject)」。
Promise.resolve()
返回一個以給定值解析後的Promise物件。但如果這個值是個thenable(即帶有then方法),返回的promise會「跟隨」這個thenable的物件,採用它的最終狀態(指resolved/rejected/pending/settled);如果傳入的value本身就是promise物件,則該物件作為Promise.resolve方法的返回值返回;否則以該值為成功狀態返回promise物件。
Promise.reject()
返回一個帶有拒絕原因reason引數的Promise物件。

4.2 將回撥地獄中的例子,改寫為Promise的形式

4.2-1.png
可以看到使用 Promise後,邏輯變得非常直觀
寫得更完整一些
4.2-2.png
Promise套Promise時,也就是Promise鏈的時候——注意資訊的傳遞
一個失敗的例子,當我們使用Promise鏈的時候,如果每一步都需要上一步的資料時,就需要傳參,成功通過resolve傳參,失敗通過reject傳參,如果忘記傳參,就得不到想要的結果。
resolve把成功的資料返回給下一個回撥
reject把失敗的資料返回給下一個回撥。
4.2-3.png
給這裡的resolve傳一個參
4.2-4.png
改成失敗的例子
先不給reject傳參,如果失敗的話,下一個回撥拿不到資料
4.2-5.png
給 reject傳參
4.2-6.png
我們可以看到,即使是走的失敗回撥,下一個成功回撥還是執行了,由於 不知道() 預設返回undefined, 相當於失敗已經處理了,在成功和失敗都被處理的情況下,下一個回撥會執行的。
改成符合預期的,即失敗不呼叫。
4.2-7.png
失敗不呼叫的簡寫形式
4.2-8.png
上述情況執行後 .then(除了狗呢)裡面的成功回撥沒有執行,我們增加一個失敗回撥看看
4.2-9.png
同樣也可以返回 resolve,讓後面成功回撥可以執行
4.2-10.png

4.3 應用

載入圖片
將圖片的載入寫成一個Promise,一旦載入完成,Promise的狀態就發生變化。

const preloadImage = function (path) {
  return new Promise(function (resolve, reject) {
    const image = new Image();
    image.onload  = resolve;
    image.onerror = reject;
    image.src = path;
  });
};

Generator 函數與 Promise 的結合(詳情見參考連結,阮一峰的教學)

5. 幹掉Promise中的回撥

5.1 await

成功的情況
5.1-1.png
失敗的情況
利用 try catch
5.1-2.png
await 配合 try catch使用,比較完整

6. 總結

能利用Promise物件,把普通函數改成返回Promise的形式,解決回撥地獄的問題。
明白Promise的成功失敗呼叫邏輯,可以靈活的進行調整。
理解核心知識,先用起來,慢慢整合吸收知識。

以上就是範例解析ES6 Promise的原理和使用的詳細內容,更多請關注TW511.COM其它相關文章!