天天看點

關于Promise的了解關于Promise的了解

關于Promise的了解

為什麼要發明promise?

在promise發明之前,使用回調函數和事件來實作異步,且發現存在弊端。promise是Javascript關于異步程式設計的一種解決方案,可以将promise了解為一個容器。

promise的原理(一)

我們通過一段代碼來了解:

class Promise {
    callbacks = [];
    constructor(fn) {
        fn(this._resolve.bind(this));
    }
    then(onFulfilled) {
        this.callbacks.push(onFulfilled);
    }
    _resolve(value) {
        this.callbacks.forEach(fn => fn(value));
    }
}

//Promise應用
let p = new Promise(resolve => {
    setTimeout(() => {
        console.log('done');
        //console.log(resolve);
        resolve('5秒');
    }, 5000);
}).then((tip) => {
    console.log(tip);
})
           

1.首先執行構造函數constructor,傳入函數(箭頭函數)作為參數,且傳入函數的參數是resolve函數。

2.執行then方法,将以下函數push進callbacks數組但還不執行。

(tip) => {
    console.log(tip);
}
           

3.此時就開始執行以下的函數體:

setTimeout(() => {
        console.log('done');
        resolve('5秒')
        }, 5000);
           

5秒後先輸出done,再執行resolve這個方法周遊callbacks數組,執行callbacks中的唯一一個函數,即then方法裡面的函數輸出value,且value=‘5秒’。

  這個過程可以用如下圖進行解釋:

  

關于Promise的了解關于Promise的了解

  先将then方法中的函數加入回調系統資料庫(callbacks),再通過resolve執行回調函數。

promise的原理(二)

遇到then鍊式調用的情況,通過在Promise的then中添加return this。代碼如下:

class Promise {
    callbacks = [];
    constructor(fn) {
        fn(this._resolve.bind(this));
    }
    then(onFulfilled) {
        this.callbacks.push(onFulfilled);
        return this;
    }
    _resolve(value) {
        this.callbacks.forEach(fn => fn(value));
    }
}

//Promise應用
let p = new Promise(resolve => {
    setTimeout(() => {
        console.log('done');
        //console.log(resolve);
        resolve('5秒');
    }, 5000);
}).then((tip) => {
    console.log('then1',tip);
}).then((tip) => {
    console.log('then2',tip);
})
           
關于Promise的了解關于Promise的了解

每次調用then将函數注冊回調,再傳回對象執行個體,再次調用then。

promise的原理(三)

但是有個問題,如果代碼如下時(由于沒有設定定時器,造成then沒有執行的情況):

class Promise {
    callbacks = [];
    constructor(fn) {
        fn(this._resolve.bind(this));
    }
    then(onFulfilled) {
        this.callbacks.push(onFulfilled);
    }
    _resolve(value) {
        this.callbacks.forEach(fn => fn(value));
    }
}

//Promise應用
let p = new Promise(resolve => {
        console.log('done');
        resolve('5秒');
}).then((tip) => {
    console.log(tip);
})
           

結果是隻列印了done,沒有列印 5秒。原因是沒有執行then,使得callbacks空數組。

解決方案:

class Promise {
    callbacks = [];
    constructor(fn) {
        fn(this._resolve.bind(this));
    }
    then(onFulfilled) {
        this.callbacks.push(onFulfilled);
    }
    _resolve(value) {
      setTimeout(()=>{this.callbacks.forEach(fn => fn(value))});
        }
}
//Promise應用
let p = new Promise(resolve => {
        console.log('done');
        resolve('5秒');
}).then((tip) => {
    console.log(tip);
})
           

在resolve中添加定時器,保證resolve執行時,then已經執行完。

promise的原理(四)

但是又有問題出現了,如果代碼如下:

let p = new Promise(resolve => {
    console.log('同步執行');
    resolve('同步執行');
}).then(tip => {
    console.log('then1', tip);
}).then(tip => {
    console.log('then2', tip);
});
//看這裡
setTimeout(() => {
    p.then(tip => {
        console.log('then3', tip);
    })
});
           

由于resolve設定了定時器,導緻then3不能執行。

解決方案:

增加狀态(pending、fulfilled、rejected),且fulfilled、rejected隻能由pending轉化。

class Promise {
    callbacks = [];
    state = 'pending';//增加狀态
    value = null;//儲存結果
    constructor(fn) {
        fn(this._resolve.bind(this));
    }
    then(onFulfilled) {
        if (this.state === 'pending') {//在resolve之前,跟之前邏輯一樣,添加到callbacks中
            this.callbacks.push(onFulfilled);
        } else {//在resolve之後,直接執行回調,傳回結果了
            onFulfilled(this.value);
        }
        return this;
    }
    _resolve(value) {
        this.state = 'fulfilled';//改變狀态
        this.value = value;//儲存結果
        this.callbacks.forEach(fn => fn(value));
    }
}

let p = new Promise(resolve => {
    setTimeout(() => {
        console.log('done');
        resolve('5秒')
    }, 5000);
}).then((tip) => {
    console.log('then1',tip);
}).then((tip) => {
    console.log('then2',tip);
});

setTimeout(() => {
    p.then(tip => {
        console.log('then3', tip);
    })
});

           

參考: https://zhuanlan.zhihu.com/p/58428287