最近買了掘金小冊,裏面有關於promise的實現。看了半天,終於理解簡單的promise。並且我相信工做中也不會說讓你完整實現一個。因此我在理解原理以後,我就再也不深刻了。前端
這裏主要是Promise/A+ 規範,可是從簡單promise上去理解,實際上咱們須要知道的是三個狀態面試
const pending = 'pending'; //等待
const resolved = 'resolved'; //成功
const rejected = 'rejected'; //失敗複製代碼
很簡單的三個狀態。數組
我在沒有實現函數以前是這樣想的。promise
一、自己是鏈式調用bash
二、鏈式調用和回調函數相似函數
核心在於和回調函數相似。promise實際上也是相似的操做方式。ui
回顧下回調函數:回調函數是在當你的操做或者結果須要到達這個執行結果的時候你把函數看成參數的形式執行,而後能夠獲得結果。this
說白了就是在恰達的時機去執行你的函數。spa
這裏來一個簡單的回調函數。看看prototype
function huidiao(a, callback) {
callback(a * 10);
}
huidiao(20, e => {
console.log(e);
});複製代碼
function MyPromise(fn) {
const that = this;
that.state = pending;
that.value = null;
that.resolvedCallbacks = [];
that.rejectedCallbacks = [];
//成功的回調函數
// 失敗的回調函數
}複製代碼
這裏this不須要我解釋吧。
value是到時候的執行結果
下面兩個爲何是數組呢?這裏確定有人會疑問,我提早說一下,這裏是放成功執行函數和失敗執行函數的。
//成功的回調函數
function resolve(value) {
if(that.state === pending) {
that.state = resolved;
that.value = value;
that.resolvedCallbacks.map(cb => cb(that.value));
}
}
// 失敗的回調函數
function reject(value) {
if(that.state === pending) {
that.state = rejected;
that.value = value;
that.rejectedCallbacks.map(cb => cb(that.value));
}
}複製代碼
這裏能看到會有傳入值,還有是執行函數,和改變狀態。
改變狀態和給值沒必要多說,至於爲何是對數組進行map而後執行是由於後面會存放進來函數,函數須要執行。
埋個坑。後面解釋
try {
fn(resolve, reject)
} catch (e) {
reject(e);
}複製代碼
MyPromise.prototype.then = function (onFulfilled, onRejected) {
const that = this;
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
onRejected = typeof onRejected === 'function' ? onRejected : r => { throw r };
if (that.state === pending) {
that.resolvedCallbacks.push(onFulfilled);
that.rejectedCallbacks.push(onRejected);
}
if (that.state === resolved) {
onFulfilled(that.value);
}
if (that.state === rejected) {
onRejected(that.value);
}
};複製代碼
這裏onFulfilled, onRejected是規範裏面的命名方式,判斷是不是函數是爲了阻止非回調函數的執行
new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 0)
}).then((value) => {
console.log(value)
});複製代碼
結果是正常輸出1
看了上面一堆代碼是否是不理解,也感受懵逼呢?
這裏我來說一下執行順序,你們就理解了。
一、根據鏈式調用順序,先會執行then的方法。這時候是確定是會執行到pending狀態,那麼就會把
(value) => {
console.log(value)
}複製代碼
傳入resolvedCallbacks給進入數組當中
二、函數解析的時候是會把預先定義好的變量等都完成,函數也會提早解析好,關鍵是在這裏會執行回調函數
try {
fn(resolve, reject)
} catch (e) {
reject(e);
}複製代碼
上文中
setTimeout(() => {
resolve(1)
}, 0)複製代碼
是被fn()函數執行了。注意是經過resolve執行傳入結果。這裏自己是回調函數的概念。
二、resolve函數獲得結果,判斷以後發現當前狀態是等待狀態那麼就會執行對應的結果
三、最後經過鏈式調用的回調方式來獲得結果
四、至於爲何是數組或者這麼多狀態,那是由於咱們還有catch方法。若是直接就執行了,那麼就結果不對了。
代碼自己根據《前端面試之道》小冊來編寫。
推廣下個人摸魚羣:797957786