全部問題均可以經過加一層中間層來解決。
Promises/A+promise
簡易的,不作廢話直接開始 :)框架
const p = new Promise((resolve, reject)=>{ // 若是操做成功則調用 resolve 並傳入 value // 若是操做失敗則調用 reject 並傳入 reason });
一般咱們都會使用上述方法獲取 Promise 實例:在構造函數種傳入一個 executor 方法,當同步/異步的任務完成時調用 resolve,失敗時調用 reject,簡單易懂,在此很少贅述。異步
一個 Promise 能夠理解爲一個狀態機,相應的 API 接口要麼用於改變狀態機的狀態,要麼在到達某個狀態時被觸發,所以首先須要實現的是 Promise 的狀態信息:函數
const PENDING = 0 const FULFILLED = 1 const REJECTED = 2
而且只存在 PENDING => FULFILLED 或者 PENDING => REJECTED 的狀態轉移。測試
首先實現構造函數的框架以下:this
class Promise { constructor(executor) { this.status = PENDING; // 實例當前的狀態 this.data = undefined; // Promise 返回的值 this.defered = []; // 回調函數集 executor(resolve, reject); // 執行 executor 並傳入相應的參數 } }
上述代碼基本實現 Promise 構造函數的主題部分,可是存在三個問題:code
修修補補以下:對象
class Promise { constructor(executor) { this.status = PENDING; this.data = undefined; this.defered = []; try { // bind, bind, bind! executor(this.resolve.bind(this), this.reject.bind(this)); } catch (e) { this.reject(e); } } resolve(value) { // TODO } reject(reason) { // TODO } }
接下來實現 resolve 和 reject 方法,基本上就是在判斷狀態爲 PENDING 以後把狀態改成相應的值,並把對應的 value 和 reason 存在 self 的 data 屬性上面,最後執行相應的回調函數,邏輯很簡單:接口
resolve(value) { if (this.status === PENDING) { this.status = FULFILLED; this.data = value; this.defered.forEach(i => i.onfulfiled(value)); } } reject(reason) { if (this.status === PENDING) { this.status = REJECTED; this.data = reason; this.defered.forEach(i => i.onrejected(reason)); } }
Promise 對象有一個 then 方法,用來註冊在這個 Promise 狀態肯定後的回調,很明顯 then 方法須要寫在原型鏈上,Promise 總共有三種可能的狀態,在 then 方法中咱們分別用三個判斷分支來處理,而且都分別返回一個新的 Promise 實例。事件
then(onResolved, onRejected) { // 若是 then 的參數不是 function 則咱們須要忽略它 onResolved = typeof onResolved === 'function' ? onResolved : function(v) {}; onRejected = typeof onRejected === 'function' ? onRejected : function(r) {}; switch (this.status) { case FULFILLED: return new Promise((resolve, reject) => { // TODO }); case REJECTED: return new Promise((resolve, reject) => { // TODO }); case PENDING: return new Promise((resolve, reject) => { // TODO }); } }
完整的實現以下,其中須要注意的是,若是 onResolved 的返回值是一個 Promise 對象,則直接取它的結果作爲新的 Promise 實例的結果:
then(onResolved, onRejected) { onResolved = typeof onResolved === 'function' ? onResolved : function(v) {}; onRejected = typeof onRejected === 'function' ? onRejected : function(r) {}; switch (this.status) { case FULFILLED: return new Promise((resolve, reject) => { try { const r = onResolved(this.data); r instanceof Promise && r.then(resolve, reject); resolve(r); } catch (e) { reject(e); } }); case REJECTED: return new Promise((resolve, reject) => { try { const r = onRejected(this.data); r instanceof Promise && r.then(resolve, reject); } catch (e) { reject(e); } }); case PENDING: return new Promise((resolve, reject) => { const onfulfiled = () => { try { const r = onResolved(this.data); r instanceof Promise && r.then(resolve, reject); } catch (e) { reject(e); } }; const onrejected = () => { try { const r = onRejected(this.data); r instanceof Promise && r.then(resolve, reject); } catch (e) { reject(e); } }; this.defered.push({ onfulfiled, onrejected }); }); } }
至此實現一個簡易的 Promise,使用以下測試用例驗證:
new Promise((resolve, reject) => { setTimeout(() => { resolve(1); }, 1000); }).then((res) => { console.log(res); return new Promise((resolve, reject) => { setTimeout(() => { resolve(2); }, 1000); }); }).then((res) => { console.log(res); return new Promise((resolve, reject) => { setTimeout(() => { resolve(3); }, 1000); }); }).then((res) => { console.log(res); }); // 1 // 2 // 3 // [Finished in 3.1s]
new Promise((resolve) => { resolve(); }) .then(() => { console.log('1'); }) .then(() => { console.log('2'); }); console.log('3');
執行上面的代碼會發現輸出的順序是「1, 2, 3」,而不是正確的「3, 1, 2」,顯然是由於咱們沒有在 Promise 的 resolve 方法中異步的調用回調函數集致使的,固然解決這個問題也很簡單,就是使用 setTimeout,可是這樣實現的話並不符合 Promise 在事件循環中的優先級,因此暫時忽略。
new Promise((resolve) => { resolve(8); }) .then() .then() .then((value) => { console.log(value) });
上面的代碼使用咱們剛剛實現的 Promise 會打印 undefined,然而這並非咱們指望獲得的結果,咱們但願的是8這個值會穿過兩個 then 到達鏈尾的 then 的執行函數裏,其輸出應該和這段代碼一致:
new Promise((resolve) => { resolve(8); }) .then((value) => { return value; }) .then((value) => { return value; }) .then((value) => { console.log(value); });
其實要實現這個功能十分簡單,只要把 then 的兩個參數的默認值作簡單的修改:
onResolved = typeof onResolved === 'function' ? onResolved : function(v) { return v; }; onRejected = typeof onRejected === 'function' ? onRejected : function(r) { return r; };