lesson01 Promise

287 阅读3分钟

promise A+ 规范

术语

  1. promise是一个有then方法的对象或者函数,行为遵循promiseA+规范
  2. thanable 是一个有then方法的对象或者函数
  3. value 是 promise 状态成功的值,也就是resolve的参数,包括各种数据类型, 或者是一个promise
  4. reason 是 promise 状态失败时的值, 也就是rejected的参数,表示拒绝的原因
  5. exception throw 抛出去的异常

规范

Promise status

promise 有三种状态,要注意他们之间的流转关系

  1. pending

    • 初始的状态
    • 一个promise在被resolve之前或者rejected之前,都处于这个状态
    • 可以通过 resolve -> fullfilled
    • 可以通过 reject -> rejected
  2. fullfilled

    • 最终态,不可该改变
    • 一个promise经过resolve之后变成这个状态,必须拥有一个value值 resolve() 相当于 resolve(undefined)
  3. rejected

    • 最终态,不可该改变
    • 一个promise经过reject之后变成这个状态
    • 必须拥有一个value值

then

promise 应该提供一个then方法,用来访问最终的结果,无论是value还是reason

promise.then(onFullfilled, onReject)
  1. 参数要求

onFullfilled, onReject 必须是函数类型,如果不是函数,应该被忽略

  1. onFullfilled 特性

    • 在promise变成fullfilled时,应该调用哦那onFullfilled, 参数被调用
    • 在fullfilled之前,不应该被调用
    • 只能被调用一次
  2. onRejected特性

    • 在promise变成rejected时,应该调用哦那onRejected, 参数被调用
    • 在rejected之前,不应该被调用
    • 只能被调用一次
  3. onFullfilled 和 onRejected 应该是微任务

    • queuecrotask实现微任务的调用
  4. then方法可以被调用多次

    • promise 变成 fullfilled之后,所有onFullfilled的回调都应该按照then的顺序执行

       const promise = new Promise();
       promise.then();
       promise.then();
      
    • 在实现promise的时候需要一个数组来存储 onFullfilled 的回调

    • promise 变成 rejected之后,所有 onRejected 的回调都应该按照then的顺序执行, 也需要一个数组来存储它的回调

  5. 返回值

      promise2 = promise.then(onFullfilled, onRejected)
    
    • then 的返回值是一个promise
    • onFullfilled 和 onRejected 执行结果为x, 调用resolvePromise
    • 如果onFullfilled 和 onRejected 执行异常, promise2需要被reject
    • 如果 onFullfilled 不是一个函数,promise2就会以 promise1的value 触发 fulfilled
    • 如果 onRejected 不是一个函数,promise2就会以 promise1的 reason 触发 rejected
  6. resolvePromise

    resolvePromise(promise2, x, resolve, reject)
    
    • 如果 promise2 与 x 相等,那么 reject TypeError

    • 如果 x 是一个promise

      • 如果x是pending, promise的状态 直到 x 变成了fulfilled / rejected
      • 如果x 是 fulfilled, fulfill promise with same value
      • 如果x 是 rejected, reject promise with same reason
    • 如果 x 是一个object或者是一个function

      let then = x.then

      如果x.then这一步出错了, reject(e)

      如果 then 是一个函数, then.call(x, resolvePromiseFn, rejectPromiseFn)

      resovlePromiseFn的入参是 y ,执行 resolvePromise(promise2, y, resolve, reject)

      如果调用 then 的时候抛出了异常,reject reason

  7. 实现一个 promise

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected'

class LPromise {
 FULFILLED_CALLBACK_LIST = [];
 REJECTED_CALLBACK_LIST = [];
 _status = PENDING;
 constructor (fn) {
   this.status = PENDING;
   this.value = null;
   this.reason = null;
   try {
     fn(this.resolve.bind(this), this.reject.bind(this))
   } catch (error) {
     this.reject(error);
   }
 }

 get status () {
   return this._status;
 }
 set status (newStatus) {
   this._status = newStatus;
   switch (newStatus) {
     case FULFILLED: {
       this.FULFILLED_CALLBACK_LIST.forEach(fn => {
         fn(this.value);
       });
       break;
     }
     case REJECTED: {
       this.REJECTED_CALLBACK_LIST.forEach(fn => {
         fn(this.reason);
       });
       break;
     }
   }
 }

 resolve (value) {
   if (this.status === PENDING) {
     this.value = value;
     this.status = FULFILLED;
   }
 }
 reject (reason) {
   if (this.status === PENDING) {
     this.reason = reason;
     this.status = REJECTED;
   }
 }
 
 // 返回值是一个 promise
 then (onFulfilled, onRejected) {
   const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : value => value;
   const realOnRejected = this.isFunction(onRejected) ? onRejected : reason => { throw reason };
   const promise = new LPromise((resolve, reject) => {

     const fulfilledMicrotask = () => {
       queueMicrotask(() => {
         try {
           const x = realOnFulfilled(this.value);
           this.resovlePromise(promise, x, resolve, reject)
         } catch (error) {
         reject(error);
         } 
       })
     }
     
     const rejectedMicrotask = () => {
       queueMicrotask(() => {
         try {
           const x = realOnRejected(this.reason)
           this.resovlePromise(promise, x, resolve, reject)
         } catch (error) {
           reject(error);
         }
       })
     }

     switch (this.status) {
       case FULFILLED: {
         fulfilledMicrotask()
         break;
       } 
       case REJECTED: {
         rejectedMicrotask();
         break;
       }
       case PENDING: {
         this.FULFILLED_CALLBACK_LIST.push(realOnFulfilled)
         this.REJECTED_CALLBACK_LIST.push(realOnRejected)
       }

     }
   });
   return promise;
 }

 catch (onRejected) {
   this.then(null, onRejected)
 }

 resovlePromise (promise2, x, resolve, reject) {
    if (promise2 === x) {
      return reject(new TypeError('the promise and return value are the same'));
    }

    // 如果 x 是 promise
    if (x instanceof LPromise) {
      queueMicrotask(() => {
         x.then((y) => {
           this.resovlePromise(promise2, y, resolve, reject);
         }, reject)
      })
    } else if (typeof x === 'object' || this.isFunction(x)) {
      if (x === null) {
        return resolve(x);
      }
      
      let then = null;
      
      try {
        then = x.then;
      } catch (error) {
         return reject(error)  
      }

     if (this.isFunction(then)) {
       let called = false;
       try {
         then.call(
           x,
           y => {
             if (called) return
             called = true;
             this.resovlePromise(promise2, y, resolve, reject)
           },
           y => {
             if (called) return
             called = true;
             reject(y);
           } 
         )
       } catch (error) {
         if (called) return

         reject(error)
       }
     } else {
         resolve(x)
     }
   } else {
      resolve(x)
   }
 }

 isFunction (value) {
   return typeof value === 'function';
 }

 static resolve (value) {
   if (value instanceof LPromise) {
     return value;
   }
   return new LPromise (r => r(value))
 }

 static resolve (reason) {
   if (value instanceof LPromise) {
     return value;
   }
   return new LPromise ((r, j) => j(reason))
 }
} 


const promise = new LPromise((r, j) => {
 r(111)
})

promise.then(e => {
 console.log(e);
 return e;
}).then(e => {
 console.log(e);
 return e;
})