promise
1 /* 2 尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理. 3 */ 4 5 6 // 定义三个状态 7 const PENDING = "PENDING"; 8 const RESOLVED = "RESOLVED"; 9 const REJECTED = 'REJECTED'; 10 function resolvePromise(x, promise2, resolve, reject) { 11 //判断x === promise, 抛出类型错误 12 if (x === promise2) { 13 console.log('======') 14 return reject(new TypeError('类型错误')) 15 } 16 // 允许状态改变一次 17 let called = false; 18 19 20 21 try { 22 //判断x是否包含then属性,thenable 23 if (typeof x === 'object' && x !== null) { 24 const then = x.then; 25 if (typeof then === "function") { 26 // console.log(typeof then) 27 then.call(x, v => { 28 if (called) return; 29 called = true; 30 resolvePromise(v, promise2, resolve, reject) 31 }, r => { 32 if (called) return; 33 called = true; 34 reject(r) 35 }) 36 } else { 37 if (called) return; 38 called = true; 39 resolve(x) 40 } 41 } else { 42 if (called) return; 43 called = true; 44 resolve(x) 45 } 46 } catch (e) { 47 if (called) return; 48 called = true; 49 reject(e) 50 } 51 } 52 class Promise { 53 constructor(exectuor) { 54 try { 55 //捕获执行器错误 56 exectuor(this.resolve, this.reject) 57 } catch (e) { 58 this.reject(e) 59 } 60 } 61 62 status = PENDING; 63 value = null; 64 reason = null; 65 //存储失败和成功的回调 66 onFullFilledCallbacks = []; 67 onRejectedCallbacks = []; 68 69 static all (args) { 70 return new Promise((resolve, reject) => { 71 args.reduce((prev, curr, i, arr) => { 72 if (curr instanceof Promise) { 73 curr.then((v) => { 74 prev[i] = v; 75 if (prev.length === arr.length) { 76 resolve(prev) 77 } 78 }, r=> { 79 reject(r) 80 }) 81 } else { 82 prev[i] = curr; 83 } 84 return prev; 85 }, []) 86 }) 87 } 88 static resolve (v) { 89 if (v instanceof Promise) return v; 90 return new Promise((resolve ,reject) => resolve(v)); 91 } 92 static reject(r) { 93 return new Promise((resolve,reject)=>{ 94 reject(r) 95 }) 96 } 97 static allSettled (args) { 98 return new Promise((resolve, reject) => { 99 function addData(prev, index, value){ 100 prev[index] = value; 101 if (prev.length === args.length) { 102 resolve(prev) 103 } 104 } 105 args.reduce((prev, curr, index, arr) => { 106 if (curr instanceof Promise) { 107 curr.then(res => { 108 addData(prev, index, { 109 value: res, 110 status: 'fulfilled' 111 }) 112 }, r => { 113 addData(prev, index, { 114 reason: r, 115 status: 'rejected' 116 }) 117 }) 118 } else { 119 addData(prev, index, { 120 reason: curr, 121 status: 'fulfilled' 122 }) 123 } 124 }) 125 }) 126 } 127 128 static race(args) { 129 return new Promise((resolve, reject) => { 130 args.forEach((item) => { 131 if (item instanceof Promise) { 132 item.then(v => { 133 resolve(v) 134 }, r => { 135 reject(r) 136 }) 137 } else { 138 resolve(item) 139 } 140 }) 141 }) 142 } 143 144 finally (cb) { 145 return this.then(v => { 146 return Promise.resolve(cb()).then(() => v); 147 }, r => { 148 return Promise.resolve(cb()).then(() => { throw r }) 149 }) 150 } 151 152 resolve = (v) => { 153 154 //只有状态为pending才执行 155 if (this.status === PENDING) { 156 this.status = RESOLVED; 157 this.value = v; 158 this.onFullFilledCallbacks.forEach(c => c()) 159 } 160 } 161 162 reject = (r) => { 163 if (this.status === PENDING) { 164 this.status = REJECTED; 165 this.reason = r; 166 this.onRejectedCallbacks.forEach(c => c()) 167 } 168 } 169 170 then(onFullFilled, onRejected) { 171 //onFullFilled onRejected类型判断 172 if (typeof onFullFilled !== 'function') onFullFilled = v => v; 173 if (typeof onFullFilled !== 'function') { 174 onRejected = r => { 175 throw r; 176 } 177 } 178 const promise2 = new Promise((resolve, reject) => { 179 if (this.status === RESOLVED) { 180 // Promise为微任务,所以放到微任务队列执行 181 queueMicrotask(() => { 182 try { 183 const x = onFullFilled(this.value); 184 resolvePromise(x, promise2, resolve, reject) 185 } catch (e) { 186 reject(e) 187 } 188 }) 189 } 190 191 if (this.status === REJECTED) { 192 queueMicrotask(() => { 193 try { 194 const x = onRejected(this.reason) 195 resolvePromise(x, promise2, resolve, reject) 196 } catch (e) { 197 reject(e) 198 } 199 }) 200 } 201 202 if (this.status === PENDING) { 203 //如果状态为pending,则执行方法放入数组中,等待resolve或reject时候执行 204 this.onFullFilledCallbacks.push(() => { 205 queueMicrotask(() => { 206 try { 207 const x = onFullFilled(this.value); 208 resolvePromise(x, promise2, resolve, reject) 209 } catch (e) { 210 reject(e) 211 } 212 }) 213 }) 214 215 this.onRejectedCallbacks.push(() => { 216 queueMicrotask(() => { 217 try { 218 const x = onRejected(this.reason); 219 resolvePromise(x, promise2, resolve, reject) 220 } catch (e) { 221 reject(e) 222 } 223 }) 224 }) 225 } 226 }) 227 return promise2; 228 } 229 } 230 231 Promise.deferred = function() { 232 var result = {}; 233 result.promise = new Promise(function(resolve, reject){ 234 result.resolve = resolve; 235 result.reject = reject; 236 }); 237 238 return result; 239 } 240 241 module.exports = Promise;