實現功能如下:
- Promise建構函式
- promise例項then方法
- pomise例項catch方法
- promise例項finally方法
- Promise靜態resolve方法
- Promise靜態reject方法
- Promise靜態all方法
備註:參照渡一教育影片
程式碼:1 const Pending = 'pending'; 2 const FullFiled = 'fulfilled'; 3 const Rejected = 'rejected'; 4 class MyPromise { 5 #status = Pending; 6 #value = ''; 7 #taskList = []; 8 constructor(executor) { 9 try { 10 executor(this.#resolve, this.#reject); 11 } catch (error) { 12 this.#reject(error); 13 } 14 15 } 16 #resolve = (data) => { 17 this.#changeState(FullFiled, data); 18 } 19 20 #reject = (reason) => { 21 this.#changeState(Rejected, reason); 22 } 23 24 #changeState = (status, value) => { 25 if (status === Pending) return; 26 this.#status = status; 27 this.#value = value; 28 this.#eventLoop(); 29 } 30 31 // 判斷then中的返回值是否複合PromiseA+規範 32 #isPromiseA = (callBack) => { 33 if (callBack !== null && (typeof callBack === 'object' || typeof callBack === 'array')) { 34 return typeof callBack.then === 'function'; 35 } 36 return false; 37 } 38 39 // 手動將promise.then中的函式放入微佇列中 40 // nodeJS環境使用process.nextTick() 41 // 瀏覽器環境使用MutationObserver() 42 #addMicroTaskList = (callBack) => { 43 if (typeof process === 'object' && typeof process.nextTick === 'function') { 44 process.nextTick(callBack); 45 return; 46 } 47 if (typeof MutationObserver === 'function') { 48 let m = new MutationObserver(callBack); 49 let div = document.createElement("div"); 50 m.observe(div, { 51 childList: true 52 }); 53 div.innerText = "1"; 54 return; 55 } 56 // 其他環境 57 setTimeout(callBack, 0); 58 } 59 60 // promise.then中的函式需要放到微佇列執行, 61 // then中的引數有三種情況 62 // 1. 引數不是函式,promise穿透到下一個then 63 // 2. 引數是一個函式, 64 // 2.1 函式的返回值不是promise,直接resolve(this.value) 65 // 2.2 函式的返回值是promise, 呼叫promise.then() 66 #handelOneTask = (callBack, resolve, reject) => { 67 this.#addMicroTaskList(() => { 68 if (typeof callBack === 'function') { 69 try { 70 const result = callBack(this.#value); 71 if (this.#isPromiseA(result)) { 72 result.then(resolve, reject); 73 } else { 74 resolve(result); 75 } 76 } catch (error) { 77 reject(error); 78 } 79 80 } else { 81 // 如果then中的兩個引數不是函式,則promise穿透到下一層then 82 if (this.#status === FullFiled) { 83 resolve(this.#value); 84 } else if (this.#status === Rejected) { 85 reject(this.#value); 86 } 87 } 88 }); 89 } 90 91 // 每次呼叫then方法和promise的狀態發生改變時,執行then中的回撥函式 92 #eventLoop = () => { 93 if (this.#status === Pending) return; 94 while (this.#taskList.length) { 95 const { successCal, errorCal, resolve, reject } = this.#taskList.shift(); 96 switch (this.#status) { 97 case FullFiled: 98 this.#handelOneTask(successCal, resolve, reject); 99 break; 100 case Rejected: 101 this.#handelOneTask(errorCal, resolve, reject); 102 break; 103 default: 104 break; 105 } 106 107 } 108 } 109 110 // then方法接收resolve和reject的回撥函式 111 then = (successCal, errorCal) => { 112 return new MyPromise((resolve, reject) => { 113 this.#taskList.push({ successCal, errorCal, resolve, reject }); 114 this.#eventLoop(); 115 }) 116 } 117 118 catch = (callBack) => { 119 return this.then(undefined, callBack); 120 } 121 122 finally = (callBack) => { 123 return this.then((data) => { 124 callBack(); 125 return data; 126 }, (err) => { 127 callBack(); 128 throw err; 129 }) 130 } 131 132 static resolve = (value) => { 133 if (value instanceof MyPromise) return value; 134 let _resolve, _reject; 135 const p = new MyPromise((resolve, reject) => { 136 _resolve = resolve; 137 _reject = reject; 138 }); 139 if (p.#isPromiseA(value)) { 140 value.then(_resolve, _reject) 141 } else { 142 _resolve(value); 143 } 144 return p; 145 } 146 147 static reject = (reason) => { 148 return new MyPromise((resolve, reject) => { 149 reject(reason); 150 }) 151 } 152 153 static all = (iterable) => { 154 let _resolve, _reject; 155 const p = new MyPromise((res, rej) => { 156 _resolve = res; 157 _reject = rej; 158 }); 159 let successCount = 0; 160 let count = 0; 161 let data = []; 162 for (const item of iterable) { 163 const i = count; 164 count++; 165 MyPromise.resolve(item).then(res=>{ 166 successCount++; 167 data[i] = res; 168 if(count === successCount) { 169 _resolve(data); 170 } 171 }, _reject ) 172 }; 173 if (count === 0) { 174 _resolve(data); 175 } 176 return p; 177 } 178 } 179 180 const a = new MyPromise((resolve, reject) => { 181 // resolve(123) 182 // reject('error') 183 // setTimeout(() => { 184 // resolve(123); 185 // }, 1000); 186 // throw 'error' 187 });