首先要肯定Promise的幾個特色前端
以上就是Promise的主要部分,下面咱們就根據這些特色來實現咱們本身的promise數組
const PENDING = 'pending'; const FUFILLED = 'fufilled'; const REJECTED = 'rejected'; class MyPromise { status = PENDING; value = null; reason = null; successCallback = []; failCallback = []; constructor(executor) {//初始化的時候傳進來的執行器 try { executor(this.resolve, this.reject);//改變狀態的倆函數,一個成功,一個失敗 } catch (error) { this.reject(err);//執行器出錯的話,直接調用失敗,改變當前promise的狀態 } } resolve = (value) => {//決議函數 if (this.status !== PENDING) return;//若是狀態不是等待,證實已經執行過了,爲了符合promise一旦決議不可更改的特性,退出 this.status = FUFILLED;//更改狀態 this.value = value;//保存一下決議值 while (this.successCallback.length) this.successCallback.shift()(); //若是執行器中代碼是異步,而且綁定then函數時會把成功回調暫存起來,等執行器決議後調用經過then綁定的成功回調 //當前這個promise可能會綁定多個then函數,因此成功回調用數組存放 } reject = (reason) => {//失敗狀態函數 if (this.status !== PENDING) return;//同上面的決議函數同樣,調用過,退出 this.reason = reason;//暫存失敗緣由,方便後續使用 this.status = REJECTED;//修改狀態 while (this.failCallback.length) this.failCallback.shift()(); //和resolve同樣,不過這個是失敗的數組,依次拿出來調用 } then(successCallback, failCallback) {//then函數 successCallback = successCallback ? successCallback : value => value;//成功參數可選,沒有的話給個默認參數 failCallback = failCallback ? failCallback : reason => { throw reason }; //失敗參數可選,沒有的話給個默認手動拋錯的函數,方便後續沒傳入的時候假如報錯了,能夠鏈式傳遞 let promise2 = new MyPromise((resolve, reject) => {//聲明promise,返回,符合then老是返回promise的規則 if (this.status === FUFILLED) {//同步代碼,成功了 setTimeout(() => {///定時器添加是爲了把這個函數修改成異步執行,等待promsie2同步執行完了,聲明完畢後執行,這樣才能獲取到promise2 try { let x = successCallback(this.value);//獲取成功回調返回值 resolvePromise(promise2, x, resolve, reject); //查看是否返回的是promise而且是否循環返回當前promise,若是是返回的promise展開他,並根據狀態執行。若是是普通值,直接resolve } catch (error) { reject(error);//執行回調過程出錯了,調用reject傳遞錯誤 } }, 0) } else if (this.status === REJECTED) {//同成功邏輯大致類似,不一樣是執行回調不同,傳入回調參數不同 setTimeout(() => { try { let x = failCallback(this.reason); resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }, 0) } else {//上一個promsie執行器返回的不是當即值是一個異步操做 this.successCallback.push(() => {//把這個成功回調暫存起來,等待當前promise resolve以後調用 setTimeout(() => { try { let x = successCallback(this.value); resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }, 0) }) this.failCallback.push(() => {//把這個失敗回調暫存起來,等待當前promise resolve以後調用 setTimeout(() => { try { let x = failCallback(this.reason); resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }, 0) }) } }) return promise2; } static all(array) {//promsie中的all方法 等待數組中全部項都完成後,在執行下一步 let result = []; //放完成結果 let index = 0;//用來記錄完成了幾個 return new MyPromise((resolve, reject) => { function addData(i, data) {//i是用來記錄的下標防止順序亂了,由於數組裏有多是當即值,有多是promise,往reslut放的順序有坑你不一致 //data array數組項的執行結果 result[key] = data;//放入 index++;//標識加一 if (index === result.length) {//相等所有完成了,往下走 resolve resolve(result); } } for (let i = 0; i < array.length; i++) { //依次取出數組的項,查看是當即值仍是promise,當即值的話直接添加到result數組裏,promise的話展開它,成功了就添加到reslut裏,失敗了直接拋出reject,拋棄其餘值 let current = array[i]; if (current instanceof MyPromise) { current.then((value) => { addData(i, value) }, reason => { reject(reason) }) } else { addData(i, current) } } }) } static resolve(value) {//遵循promise中resolve規範,若是傳入是一個promise直接返回,若是不是用promise包i裹一層變成promise返回。 if (value instanceof MyPromise) return value; return new MyPromise((resolve) => resolve(value)); } finally(callBack) {//先調用then返回promise,在它的回調裏返回一個promise對象,而後調用callback並把它的返回值傳遞給promsie resolve方法,最後直接把當前promsie的成功值或失敗值日後傳遞 return this.then(() => { return MyPromise.resolve(callBack()).then(() => value); }, reason => { return MyPromise.resolve(callBack()).then(() => { throw reason }); }) } catch(failCallback) {//捕獲錯誤方法,給當前返回的promsie經過then註冊一個失敗的回調,若是當前promise失敗了就執行, //是給返回promise註冊的,每一個then方法都會返回一個新的promise,若是前面某個鏈上的then返回的promsie有錯誤的話,而且沒有使用錯誤回調捕獲的話 //咱們會經過then默認錯誤回調,依次拋錯,而後鏈式傳遞下來,知道被catch這個錯誤回調捕獲 return this.then(undefined, failCallback) } done(onFulfilled, onRejected) { //done表明promsie得結束,能夠像then方法那樣用,提供fulfilled和rejected狀態的回調函數,也能夠不提供任何參數。但無論怎樣,done都會捕捉到任何可能出現的錯誤,並向全局拋出。 this.then(onFulfilled, onRejected) .catch(function (reason) { // 拋出一個全局錯誤 setTimeout(() => { throw reason }, 0); }); } } function resolvePromise(promise2, x, resolve, reject) {//對比是否循環返回promsie的函數,判斷返回的是promsie仍是普通值得函數來進行下一步得調用 if (x === promise2) { reject(new TypeError('Chaining cycle detected for promise #<Promise>')) return; } if (x instanceof MyPromise) { x.then(value => resolve(value), reason => reject(reason)) } else { resolve(x); } }
代碼裏的每一行都會有個人註釋,有興趣得同窗可下載下來run一下,看看,本身讀一讀。promise
該內容來自摘抄 拉鉤大前端訓練營異步