觀察原生promise用法,咱們能夠發現,在new Promise時候傳入了一個函數,這個函數在規範中的叫法是exector 執行器
看到這裏,咱們先有一個大概思路,構建一個本身的Promise構造函數。
javascript
// 這裏咱們建立了一個構造函數 參數就是執行器
function Promise(exector) {
}複製代碼
好的,第一步完成, 重點來了,這個Promise內部到底幹了什麼呢 能夠看到,原生的exector中傳入了兩個參數,第一個參數執行會讓promise狀態變爲resolve, 也就是成功, 第二個執行會讓函數變爲reject狀態,也就是失敗java
而且這連個形參執行以後均可以傳入參數,咱們繼續完善代碼 咱們將這兩個形參的函數封裝在構造函數內部數組
// 這裏咱們建立了一個構造函數 參數就是執行器
function Promise(exector) {
// 這裏咱們將value 成功時候的值 reason失敗時候的值放入屬性中
let self = this;
this.value = undefined;
this.reason = undefined;
// 成功執行
function resolve(value) {
self.value = value;
}
// 失敗執行
function reject(reason) {
self.reason = reason;
}
exector(resolve, reject);
}複製代碼
這裏問題來了,咱們知道,promise的執行過程是不可逆的,resolve和rejeact之間也不能相互轉化, 這裏,咱們就須要加入一個狀態,判斷當前是否在pending過程,另外咱們的執行器可能直接報錯,這裏咱們也須要處理一下。
// 這裏咱們建立了一個構造函數 參數就是執行器
function Promise(exector) {
// 這裏咱們將value 成功時候的值 reason失敗時候的值放入屬性中
let self = this;
// 這裏咱們加入一個狀態標識
this.status = 'pending';
this.value = undefined;
this.reason = undefined;
// 成功執行
function resolve(value) {
// 判斷是否處於pending狀態
if (self.status === 'pending') {
self.value = value;
// 這裏咱們執行以後須要更改狀態
self.status = 'resolved';
}
}
// 失敗執行
function reject(reason) {
// 判斷是否處於pending狀態
if (self.status === 'pending') {
self.reason = reason;
// 這裏咱們執行以後須要更改狀態
self.status = 'rejected';
}
}
// 這裏對異常進行處理
try {
exector(resolve, reject);
} catch(e) {
reject(e)
}
}複製代碼
// 咱們將then方法添加到構造函數的原型上 參數分別爲成功和失敗的回調
Promise.prototype.then = function(onFulfilled, onRejected) {
// 獲取下this
let self = this;
if (this.status === 'resolved') {
onFulfilled(self.value);
}
if (this.status === 'rejected') {
onRejected(self.reason);
}
}複製代碼
ok,咱們如今能夠本身運行試試
let promise = new Promise((resolve, reject) => {
resolve("haha");
})
promise.then(data => {
console.log(data); //輸出 haha
}, err=> {
console.log(err);
})
// 屢次調用
promise.then(data => {
console.log(data); //輸出 haha
}, err=> {
console.log(err);
})複製代碼
上面能夠注意到, new Promise中的改變狀態操做咱們使用的是同步,那若是是異步呢,咱們平時遇到的基本都是異步操做,該如何解決?promise
這裏咱們須要在構造函數中存放兩個數組,分別保存成功回調和失敗的回調
由於能夠then屢次,因此須要將這些函數放在數組中
代碼以下:bash
// 這裏咱們建立了一個構造函數 參數就是執行器
function Promise(exector) {
// 這裏咱們將value 成功時候的值 reason失敗時候的值放入屬性中
let self = this;
// 這裏咱們加入一個狀態標識
this.status = 'pending';
this.value = undefined;
this.reason = undefined;
// 存儲then中成功的回調函數
this.onResolvedCallbacks = [];
// 存儲then中失敗的回調函數
this.onRejectedCallbacks = [];
// 成功執行
function resolve(value) {
// 判斷是否處於pending狀態
if (self.status === 'pending') {
self.value = value;
// 這裏咱們執行以後須要更改狀態
self.status = 'resolved';
// 成功以後遍歷then中成功的全部回調函數
self.onResolvedCallbacks.forEach(fn => fn());
}
}
// 失敗執行
function reject(reason) {
// 判斷是否處於pending狀態
if (self.status === 'pending') {
self.reason = reason;
// 這裏咱們執行以後須要更改狀態
self.status = 'rejected';
// 成功以後遍歷then中失敗的全部回調函數
self.onRejectedCallbacks.forEach(fn => fn());
}
}
// 這裏對異常進行處理
try {
exector(resolve, reject);
} catch(e) {
reject(e)
}
}
// then 改造
Promise.prototype.then = function(onFulfilled, onRejected) {
// 獲取下this
let self = this;
if (this.status === 'resolved') {
onFulfulled(self.value);
}
if (this.status === 'rejected') {
onRejected(self.reason);
}
// 若是異步執行則位pending狀態
if(this.status === 'pending') {
// 保存回調函數
this.onResolvedCallbacks.push(() => {
onFulfilled(self.value);
})
this.onRejectedCallbacks.push(() => {
onRejected(self.reason)
});
}
}
// 這裏咱們能夠再次實驗
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
if(Math.random() > 0.5) {
resolve('成功');
} else {
reject('失敗');
}
})
})
promise.then((data) => {
console.log('success' + data);
}, (err) => {
console.log('err' + err);
})
複製代碼
咱們都熟悉Jquery,它的鏈式調用是用rerun this來作的,但是這裏卻不行,緣由文章末尾再解釋。 咱們採起返回一個新的promise對象來實現鏈式調用. 意思也就是p.then()返回一個新promise對象。dom
//給這個函數加個返回值,返回值就是一個新new的promise對象
Promise.prototype.then = function (onFulFilled, onRejected) {
let p2 = new Promise((resolve, reject) => {});
if (this.status === 'pending') {
this.onFulFilledCallbacks.push(() => {
onFulFilled(this.value)
});
this.onRejectedCallbacks.push(() => {
onRejected(this.reason)
})
} else if (this.status === 'resolved') {
onFulFilled(this.value);
} else if (this.status === 'rejected') {
onRejected(this.reason);
}
return p2;
}
複製代碼