代码改变世界

promise 简单实现

2018-08-20 22:57  罗小二  阅读(334)  评论(0)    收藏  举报

参考 Promise A+ 简单实现 promise,用的setTimeout 模拟的异步,与实际浏览器Promise 有出入(具体可以看Event loop 相关),本文只做思路理解参考。

Promise 的简单实现,主要理解规范,也可以再理解一下几个点方变记忆:

  • Promise的三种状态(pending,fulfilled,rejected), pending状态转移后不可变
  • resolve , resolve a promise with a promise
  • reject
  • Promise.prototype.then 返回一个新的promise 对象(链式操作)
  • thenable对象

 1.简单实现

 

  1 const PENDING = 'pending'
  2 const FULFILLED = 'fulfilled'
  3 const REJECTED = 'rejected'
  4 
  5 function needResolve() {
  6   throw new TypeError('need pass function to Promise')
  7 }
  8 
  9 function needuseNew() {
 10   throw new TypeError(
 11     'Promise is a constructor and should be called with the `new` keyword'
 12   )
 13 }
 14 
 15 function Promise(task) {
 16   var self = this
 17   this.state = PENDING
 18   this.value
 19   this.fulArr = []
 20   this.rejArr = []
 21 
 22   function resolve(value) {
 23     if (value != null && value.then && typeof value.then == 'function') {
 24       return value.then(resolve, reject)
 25     }
 26     setTimeout(() => {
 27       if (self.state == PENDING) {
 28         self.state = FULFILLED
 29         self.value = value
 30         self.fulArr.forEach(item => {
 31           item(self.value)
 32         })
 33       }
 34     })
 35   }
 36 
 37   function reject(reason) {
 38     setTimeout(() => {
 39       if (self.state == PENDING) {
 40         self.state = REJECTED
 41         self.value = reason
 42         self.fulArr.forEach(item => {
 43           item(self.value)
 44         })
 45       }
 46     })
 47   }
 48   typeof task !== 'function' && needResolve()
 49   !(this instanceof Promise) && needResolve()
 50   try {
 51     task(
 52       function(value) {
 53         resolve(value)
 54       },
 55       function(reason) {
 56         reject(reason)
 57       }
 58     )
 59   } catch (e) {
 60     reject(e)
 61   }
 62 }
 63 
 64 function resolvePromise(promise, x, resolve, reject) {
 65   if (promise === x) {
 66     return reject(new TypeError('do not resolve promise with itself'))
 67   }
 68   var then, called
 69   // resolve promise with promise
 70   if (x instanceof Promise) {
 71     if (x.status == PENDING) {
 72       x.then(function(y) {
 73         resolvePromise(promise, y, resolve, reject)
 74       }, reject)
 75     } else {
 76       x.then(resolve, reject)
 77     }
 78     // thenable 其它的then
 79   } else if (x !== null && (typeof x == 'function' || typeof x == 'object')) {
 80     try {
 81       // resolve promise with promise
 82       then = x.then
 83       if (typeof then === 'function') {
 84         then.call(
 85           x,
 86           function(y) {
 87             if (called) {
 88               return
 89             }
 90             called = true
 91             resolvePromise(promise, y, resolve, reject)
 92           },
 93           function(r) {
 94             if (called) {
 95               return
 96             }
 97             called = true
 98             reject(r)
 99           }
100         )
101       } else {
102         resolve(x)
103       }
104     } catch (e) {
105       if (called) {
106         return
107       }
108       called = true
109       reject(e)
110     }
111   } else {
112     resolve(x)
113   }
114 }
115 Promise.prototype.then = function(onFulfilled, onRejected) {
116   var self = this
117   onFulfilled =
118     typeof onFulfilled === 'function'
119       ? onFulfilled
120       : function(value) {
121           return value
122         }
123   onRejected =
124     typeof onRejected === 'function'
125       ? onRejected
126       : function(reason) {
127           throw reason
128         }
129   var promise2
130   if (self.state == PENDING) {
131     promise2 = new Promise(function(resolve, reject) {
132       self.fulArr.push(value => {
133         try {
134           let x = onFulfilled(value)
135           resolvePromise(promise2, x, resolve, reject)
136         } catch (e) {
137           reject(e)
138         }
139       })
140       self.reject.push(reason => {
141         try {
142           let x = onRejected(reason)
143           resolvePromise(promise2, x, resolve, reject)
144         } catch (e) {
145           reject(e)
146         }
147       })
148     })
149   }
150   if (self.state == FULFILLED) {
151     promise2 = new Promise(function(resolve, reject) {
152       setTimeout(() => {
153         try {
154           let x = onFulfilled(self.value)
155           resolvePromise(promise2, x, resolve, reject)
156         } catch (e) {
157           reject(e)
158         }
159       })
160     })
161   }
162   if (self.state == REJECTED) {
163     promise2 = new Promise(function(resolve, reject) {
164       setTimeout(() => {
165         try {
166           let x = onRejected(self.value)
167           resolvePromise(promise2, x, resolve, reject)
168         } catch (e) {
169           reject(e)
170         }
171       })
172     })
173   }
174   // then 必须返回一个新的promise
175   return promise2
176 }
177 
178 Promise.prototype.catch = function(onRejected) {
179   return this.then(null, onRejected)
180 }
181 
182 Promise.resolve = function(value) {
183   return new Promise((resolve, reject) => {
184     resolve(value)
185   })
186 }
187 Promise.reject = function(value) {
188   return new Promise((resolve, reject) => {
189     reject(value)
190   })
191 }
192 
193 function gen(time, resolve) {
194   let result = []
195   let i = 0
196   return function(index, value) {
197     if (i < time) {
198       i++
199       result[index] = value
200     } else {
201       resolve(result)
202     }
203   }
204 }
205 
206 Promise.race = function(arr) {
207   return new Promise((resolve, reject) => {
208     for (let i = 0; i < arr.length; i++) {
209       Promise.resolve(arr[i]).then(resolve, reject)
210     }
211   })
212 }
213 Promise.all = function(arr) {
214   return new Promise((resolve, reject) => {
215     let done = gen(arr.length, resolve)
216     for (let i = 0; i < arr.length; i++) {
217       Promise.resolve(arr[i]).then(function(value) {
218         done(value, i)
219       }, reject)
220     }
221   })
222 }
223 module.exports = Promise