Promise的個人理解及實踐

善良的烏賊發表於2018-02-27

基本概念

個人理解就是使用同步程式設計的寫法完成非同步程式設計操作。

const promise = new Promise((resolve, reject) => {
    //some asynchronous  code
    setTimeout(() => {
        console.log('執行完成');
        resolve('some data');
    }, 2000);
});
複製程式碼

Promise 接收一個函式作為引數,函式有兩個引數,resolvereject 分別表示非同步操作執行後成功的回撥函式和失敗的回撥函式。

Promise 例項後馬上執行。所以通常採用一個函式包含它

function runAsync() {
    return new Promise((resolve, reject) => {
        //some asynchronous  code
        setTimeout(() => {
            console.log('執行完成');
            resolve('some data');
        }, 2000);
    });
}
runAsync().then((data) => {
    console.log(data);//可以使用非同步操作中的資料
})
複製程式碼

runAsync() 執行完呼叫 then 方法,then() 就相當於我們之前寫的回撥函式。

resolve 和 reject

function paramTest(){
    return new Promise((resolve, reject) => {
        let number = Math.ceil(Math.random() * 10);
        if (number < 5) {
            resolve(number);
        }else{
            reject('out of range');
        }
    })
}
paramTest().then((number) => {
    console.log('resolved');
    console.log(number);
},(reason) => {
    console.log('rejected');
    console.log(reason);
})
複製程式碼

Promise 有三種狀態:pending(進行中)、fulfilled(已成功)和 rejected(已失敗)

paramTest() 例子有兩種情況:

  • number < 5 時,我們認為是成功情況,將狀態從 pending 變為 fulfilled
  • number >= 5 時,我們認為是失敗情況,將狀態從 pending 變為 rejected

所以paramTest() 的執行結果:

fulfilled rejected
resolved rejected
number out of range

catch的用法

我們繼續呼叫 paramTest 方法舉例

paramTest().then((number) => {
    console.log('resolved');
    console.log(number);
    console.log(data); //data為未定義
},(reason) => {
    console.log('rejected');
    console.log(reason);
}).catch((err) => {
    console.log(err);
})
複製程式碼

catch 方法其實就是 .then(null, rejection) 的別名,也是用來處理失敗失敗的回撥函式,但是還有一個作用:當 resolve 回撥中如果出現錯誤了,不會堵塞,會執行 catch 中的回撥。

all的用法

const p = Promise.all([p1, p2, p3]);

p.then(result => {
    console.log(result);
})
複製程式碼

all 方法接收一個陣列引數,陣列中每一項返回的都是 Promise 物件,只有當 p1, p2, p3 都執行完才會進入 then 回撥。p1, p2, p3 返回的資料會以一個陣列的形式傳到 then 回撥中。

const p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('p1');
    }, 1000);
})
.then(result => result)
.catch(e => e);

const p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('p2');
    }, 3000);
})
.then(result => result)
.catch(e => e);

Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
//3秒後輸出['p1', 'p2']
複製程式碼

race的用法

const p = Promise.race([p1, p2, p3]);

p.then(result => {
    console.log(result);
})
複製程式碼

race 的用法與 all 如出一轍,不同的是 all 方法需要引數的每一項都返回成功了才會執行 then;而 race 則是隻要引數中的某一項返回成功就執行 then 回撥。

以下是 race 的例子,和 all 方法對比,可以看到返回值有很明顯的區別。

const p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('p1');
    }, 1000);
})
.then(result => result)
.catch(e => e);

const p2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('p2');
    }, 3000);
})
.then(result => result)
.catch(e => e);

Promise.race([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
//1秒後輸出 'p1'
複製程式碼

點選這裡檢視本文中例項原始碼

我的實踐

resloader是基於Promise實現的一個圖片預載入並展示載入進度的外掛,猛戳這裡瞭解詳情。如果感覺還可以的話,歡迎star,也歡迎各位大佬不吝指導,感謝!

最後,感謝各位的觀看!

相關文章