手写promise第一天
2020-09-22
手写promise第一天
status:
- 用pending fulfilled rejected 3中情况分别对应 等待 成功 失败
- 状态只能由等待改变为成功或者失败 且不可逆
executor执行器:
在promise的构造函数中接收一个执行器函数 这个函数是同步执行的
这个执行器在执行时可以接收两个参数 分别是promise类中的resolve和reject
resolve&reject:
在执行器执行过程中,如果获取到需要的数据 那么执行resolve函数并将数据当做参数传入
resolve函数会将状态status改为fulfilled并且把数据存入到value中
当执行到resolve时 如果在成功回调函数队列中有回调函数 那么依次执行他们
reject同理
then:
promise中的then函数 接收两个参数分别是成功和失败的回调
同时新建一个新的promise对象 并且把这个then函数要做的事情作为 新promise对象的执行器函数传入
在这个then函数中判断当前promise的状态 如果是成功 那么执行成功回调并将value传入
成功回调函数可以返回一个值到 可以用一个变量接收作为新promise对象的resolve的参数传入
如果当前promise的状态是rejected 那么同理调用reject方法
如果状态是pending 说明当前promise还没有执行resolve或reject
将then传入的成功回调和失败回调都存到对应的回调队列里 在resolve实行的时候再去调用
resolvePromise处理器:
由于用很多种情况都要去处理resolve 所以有必要提取出来作为一个单独的函数便于复用
处理器中判断成功回调返回的值是普通值 那么可以直接执行新promise的resolve或reject方法
如果返回值是一个promise对象 那么要用这个promise对象的then方法判断这个对象目前是成功还是失败 再调用对应方法
如果返回值是一个promise对象且跟then方法中的promise对象相同 那么就死循环了 应该抛出一个错误
总结:
- 还没有处理then中的异步问题
- 还没有实现promise.all等方法
- then中逻辑还是有点乱 明天继续捋
const PENDING = 'pengding'; const FULFILLED = 'fulfilled'; const REJECTED = 'rejected'; class MyPromise { status = PENDING; // 当前promise的状态 value = undefined; // 当前promise的值 reason = undefined; // 当前promise如果失败 失败的原因 successCallbacks = []; // 如果异步 那么将回调存入到对应回调库中 rejectCallbacks = []; // promise 的构造函数接受一个执行器 这个执行器会立即执行 constructor(executor) { // 这个执行器接收两个参数 第一个参数是执行成功 第二个是失败 // 在执行器执行的过程中如果resolve执行 那么这个promise成功 executor(this.resolve, this.reject); } // 成功调用resolve方法 接收一个参数作为这个promise的返回值存在promise对象中 resolve = data => { // 一旦status状态不是pending 那么就不再执行 保证状态不可逆 if (this.status !== PENDING) return; this.status = FULFILLED; this.value = data; // 将promise成功获得的数据存在value中 // 判断成功回调函数库中是否用未执行的函数 有的话依次执行 while (this.successCallbacks.length) { this.successCallbacks.shift()(this.value); } } // 同resolve reject = reason => { if (this.status !== PENDING) return; this.status = REJECTED; this.reason = reason; while (this.rejectCallbacks.length) this.rejectCallbacks.shift()(this.reason); } // then方法 接收两个函数作为参数 第一个是成功的回调 then = (successCallback, rejectCallback) => { // then方法 返回的是一个新的promise对象 所以在执行then的时候 new一个新的promise // 同样的 这个新promise的执行器也会立即执行 let promise2 = new MyPromise((resolve, reject) => { // 当执行到then方法时候 status已经是FULFILLED说明promise已经执行成功 // 直接执行成功的回调 // 同时将成功回调的返回值传递给下一个promise的resolve方法 if (this.status === FULFILLED) { setTimeout(() => { const thenReturnVal = successCallback(this.value); resolvePromise(promise2, thenReturnVal, resolve, reject); }, 0); } else if (this.status === REJECTED) { const thenRejectVal = rejectCallback(this.reason); resolvePromise(thenRejectVal, resolve, reject); } else { // 如果执行到then的时候状态还是pending 那么 先把成功和失败的回调都存入到对应的回调库中去 // 第27行 如果resolve是异步的话 等异步结束接收到值再将回调函数从库中取出依次执行 this.successCallbacks.push(successCallback); this.rejectCallbacks.push(rejectCallback); } }); this.promise2 = promise2; return promise2; } } function resolvePromise(promise2, x, resolve, reject) { if (promise2 === x) { reject(new TypeError('重复调用自己了哦~')); } if (x instanceof MyPromise) { // 是promise对象 那需要调用Promise的then方法判断这个promise是否成功 // 如果成功 调用resolve方法 并且把值传递下去 如果失败 调用reject并且把原因传递下去 x.then(value => resolve(value), reason => reject(reason)); // x.then(resolve, reject); } else { resolve(x); } } // (resolve, reject) => {resolve('666')} 是一个执行器函数 会立即执行 // 两个参数分别是promise内部传入的 const promise = new MyPromise((resolve, reject) => { setTimeout(() => { resolve(66666); }, 2000); }) const promise33 = new MyPromise((resolve, reject) => { resolve('promise33') }) // 第一个then调用时 传入两个回调函数 // 第一个then函数内部立刻创建一个新的promise对象 并且then传入的两个函数 // 和then中的所有逻辑代码都作为新promise对象的执行器立即执行 // 如果promise成功 那么执行第一个也就是53行的successCallback let p1 = promise.then(data => { console.log(data); // 这个return会作为successCallback的返回值传入新的promise中 // 在新promise调用resolve方法时 可以当做值传递给新promise的value setTimeout(() => { return promise33; }, 2000); }, reason => { console.log(reason); }) // 执行完第一个then后 会返回一个新的promise p1.then((thenReturnVal) => { // 再次调用then是调用新promise的then方法 // 同时这个新promise的resolve方法接收上一个then方法successCallback的返回值作为value console.log(thenReturnVal); return 'then 3' }, (thenRejectVal) => { console.log(thenRejectVal); })