在ES6給我們提供的衆多新特性中, Promise一定是最好用最出色的API之一, 筆者也一直想試試寫一個自己的Promise, so let’s go!
這篇博客僅寫狀態管理, 總共分四篇博客寫完
1. Promise對於狀態的控制
從構造函數開始解析Promise
const promise = new Promise((resolve, reject) => {
console.log('我會立即執行');
})
console.log(promise);
上面是官方原版的Promise, 我們來看看控制檯輸出了啥
通過這種輸出, 我們基本可以確定一些事情來方便我們手寫Promise
1. Promise是一個構造函數, 且接受一個函數作爲參數, 他構造出的實例一開始具有兩個屬性,
一個用來表示當前狀態, 一個用來表示Promise結果
2. 寫在函數參數中的代碼會立即執行, 同時函數參數會被傳遞兩個參數,
一個resolve, 一個reject用於處理不同的情況
OK, 根據上面兩點, 我們來寫一個初步的Promise, 一步一步來嘛
1. Promise是一個構造函數, 且接受一個函數作爲參數, 他構造出的實例一開始具有兩個屬性, 一個用來表示當前狀態, 一個用來表示Promise結果
每個實例都有這兩個屬性, 代表我們要麼寫在原型上, 要麼this上, 而這兩個屬性很明顯不是繼承的, 而是出生就附着的, 所以肯定寫在this上
// 立即執行函數封閉作用域
const MyPromise = (function() {
// 當前promise狀態, 由於我們寫不了雙中括號,所以用Symbol代替了
const PromiseStatus = Symbol('PromiseStatus');
const PromiseValue = Symbol('PromiseValue');
// 立即執行函數執行 完畢以後返回一個class類給外部的MyPromise變量
return class MyPromise {
/**
*
* @param {未決(pedding)狀態下的執行函數,
* 也就是別人傳進來的函數參數} executor
*/
constructor(executor) {
// 書寫在this上的兩個屬性, 狀態一開始爲pedding
// Promise結果一開始爲undefined
this[PromiseStatus] = 'pedding';
this[PromiseValue] = undefined;
}
}
}())
寫到這, 我們看看自己寫的Promise效果吧
// 查看自己寫的Promise效果
const myPromise = new MyPromise((resolve, reject) => {
})
console.log(myPromise)
基本上兩個屬性都有了, 繼續走
2. 寫在函數參數中的代碼會立即執行, 同時函數參數會被傳遞兩個參數, 一個resolve, 一個reject用於處理不同的情況
const MyPromise = (function() {
const PromiseStatus = Symbol('PromiseStatus');
const PromiseValue = Symbol('PromiseValue');
// Promise的三種狀態
const _PEDDING = 'pedding';
const _RESOLVE = 'resolved';
const _REJECT = 'rejected';
// 改變狀態的方法
const ChangePromiseStatus = Symbol('ChangePromiseStatus');
// 要拿self來接管this指向, 否則出問題
let self = null;
// resolve和reject方法, resolve會將data傳遞過去,
// reject會將error搞過去
// resolve一旦觸發, 整個Promise實例狀態將變更爲resolved, 且不可逆
const resolve = function(_data) {
self[ChangePromiseStatus](_RESOLVE, _data);
};
// reject一旦觸發, 整個Promise實例狀態將變更爲rejected, 不可逆
const reject = (_error) => {
self[ChangePromiseStatus](_REJECT, _error);
}
return class MyPromise {
// 修改Promise狀態的方法
[ChangePromiseStatus](status, result) {
// 我們知道如果promise狀態不是pedding的話, 就是不可逆的
// 所以我們這裏要做一下短路
if(this[PromiseStatus] !== _PEDDING) return;
// 如果是pedding狀態, 則我們更改狀態也更改值
this[PromiseStatus] = status;
this[PromiseValue] = result;
}
constructor(executor) {
self = this;
this[PromiseStatus] = _PEDDING;
this[PromiseValue] = undefined;
// 2. construtor是類只要一被實例化馬上就會被執行的一個方法
// 所以我們是不是可以在這裏面直接執行以下executor
// 同時excutor執行的時候要傳遞兩個函數進去, 一個resolve, 一個reject
// 還有就是要注意的一點: 如果在executor中直接報錯了, 那麼會走進reject
// 所以我們需要捕獲一下錯誤吧
try {
executor(resolve, reject);
}catch(error) {
// 一旦報錯, 送進reject方法執行
reject(error);
}
}
}
}())
來試試看
const myPromise = new MyPromise((resolve, reject) => {
console.log('helleWorld');
console.log(age);
})
console.log(myPromise)
我們會看到控制檯如下
這個時候我們傳遞進去的函數參數就被立即走掉了, 並且報了錯