Как Promise.then реализует связанные вызовы

Promise

предисловие

мы все знаем,thenметод возвращает новыйpromiseэкземпляр, который является основой для реализации связанных вызовов.

чтобыpromiseПри изменении состояния (resolve / rejectпри вызове), а затем выполнитьthenфункция, мы используемcallbacksМассив сначала временно хранит переданную потом функцию, а затем вызывает ее при изменении состояния.

Итак, как гарантировать последнееthenМетод в предыдущемthen(возможно, асинхронно), а затем выполнить его после окончания?

Например, в следующем примере последнийthenдолжен быть напечатан через 2 секунды со значением 2

var p1 = new MyPromise((resolve, reject) => {
      console.log('hhh')
      setTimeout(() => {
        resolve(1)
      }, 1000);
    }).then(res => {
      return new MyPromise((resolve, reject) => {
        setTimeout(() => {
          resolve(res+1)
        }, 1000);
      })
    }).then(res => {
      console.log(res);
      return res;
    })

Ядро реализации связанных вызовов

будет переданоthenфункции и новыеpromiseизresolveВместеpushк предыдущемуpromiseизcallbacksВ массиве добиться эффекта связи прошлого и будущего

  • Преемственность: текущаяpromiseКогда закончите, вызовите егоresolveизменить статус, в этомresolveбудет вызываться по очередиcallbacksОбратный вызов, это будет выполненоthenметод в
  • После старта: на предыдущем шаге, когдаthenПосле выполнения метод возвращает результат. Если результатом является простое значение, он напрямую вызывает новый метод.promiseизresolve, пусть его состояние изменится, что, в свою очередь, вызовет новыйpromiseизcallbacksМетоды в массиве повторяются в цикле. . Если возвращаемый результат являетсяpromise, вам нужно дождаться его завершения, прежде чем запускать новыйpromiseизresolve, поэтому его можно найти в его результатеthenвызовите новыйpromiseизresolve

Реализация кода тогда:

then(onFulfilled, onReject){
    // 保存前一个promise的this
    const self = this; 
    return new MyPromise((resolve, reject) => {
      // 封装前一个promise成功时执行的函数
      let fulfilled = () => {
        try{
          const result = onFulfilled(self.value); // 承前
          return result instanceof MyPromise? result.then(resolve, reject) : resolve(result); //启后
        }catch(err){
          reject(err)
        }
      }
      // 封装前一个promise失败时执行的函数
      let rejected = () => {
        try{
          const result = onReject(self.reason);
          return result instanceof MyPromise? result.then(resolve, reject) : reject(result);
        }catch(err){
          reject(err)
        }
      }

      switch(self.status){
        case PENDING: 
          self.onFulfilledCallbacks.push(fulfilled);
          self.onRejectedCallbacks.push(rejected);
          break;
        case FULFILLED:
          fulfilled();
          break;
        case REJECT:
          rejected();
          break;
      }
    })
   }

Внимание ⚠️

  • несколько подрядthenМетод обратного вызова регистрируется синхронно, но регистрируется в другомcallbacksмассив, потому что каждый разthenоба возвращают новыеpromiseПримеры (см. примеры и рисунки выше)
  • После завершения регистрации выполняются асинхронные события в конструкторе, а асинхронные события вызываются последовательно после асинхронного завершения.callbacksОбратные вызовы, зарегистрированные заранее в массиве

Итак, при каких обстоятельствахcallbaksКак насчет нескольких обратных вызовов в массиве?

Например это:
p1Когда закончите, зарегистрируйтесь наp1изcallbacksФункции в выполняются последовательно
Следующий код печатает 1 через 1 секунду и 2 через 2 секунды.

var p1 = new MyPromise((resolve, reject) => {
    setTimeout(() => {
      resolve(1)
    }, 1000);
  })
var p2 =p1.then(res => {  //p1完成时的回调1
  return new MyPromise((resolve, reject) => {
    setTimeout(() => {
      resolve(res+1)
    }, 1000);
  })
}).then(res => {
  console.log(res); // 2
  return res+1;
})

p1.then(res => {  // p1完成时的回调2
    console.log(res);  // 1
})

Однако, если вы напишете:

var p1 = new MyPromise((resolve, reject) => {
      console.log('hhh')
      setTimeout(() => {
        resolve(1)
      }, 1000);
    }).then(res => {
      return new MyPromise((resolve, reject) => {
        setTimeout(() => {
          resolve(res+1)
        }, 1000);
      })
    }).then(res => {
      console.log(res); // 2
      return res+1;
    })

p1.then(res => {
    console.log(res);  // 3
})

последнийp1.thenпечатается в конце, потому чтоp1Возвращаемое значение является третьимpromise,последнийthenФункция in также прописана в третьемpromiseизcallbacksсередина.

Полная реализация обещания

 // 定义三种状态
 const PENDING = 'PENDING';
 const FULFILLED = 'FULFILLED';
 const REJECT = 'REJECT';

 class MyPromise {
   constructor(fn){
     // 初始化状态
     this.status = PENDING;
     // 将成功、失败的结果放在this上,便于then、catch访问
     this.value = null;
     this.reason = null;

     // 成功态、失败态回调函数队列,同步调用then时将对应态的函数注册进去, 在状态变更的时候调用
     this.onFulfilledCallbacks = [];
     this.onRejectedCallbacks = [];

     const resolve = (value) => {
       if(this.status === PENDING){
         this.status = FULFILLED;
         this.value = value;
         // 成功态回调函数依次执行
         this.onFulfilledCallbacks.forEach(fn => fn(this.value))
       }
     }
     const reject = (reason) => {
      if(this.status === PENDING){
        this.status = REJECT;
        this.reason = reason;
        // 失败态回调函数依次执行
        this.onRejectedCallbacks.forEach(fn => fn(this.reason))
      }
     }
     // 生成实例后立即调用fn
     // 把内部的resolve和reject传入fn,用户可调用resolve和reject
     try{
      fn(resolve, reject); 
     }catch(err){
       // fn执行出错,将错误内容用reject抛出去
       reject(err)
     }
     
   }
   then(onFulfilled, onReject){
    // 实现值穿透 当then中传入的不是函数,则这个promise返回上一个promise的值
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onReject = typeof onReject === 'function' ? onReject : reason => { throw new Error(reason) }

    // 保存前一个promise的this
    const self = this; 
    return new MyPromise((resolve, reject) => {
      // 封装前一个promise成功时执行的函数
      let fulfilled = () => {
        try{
          const result = onFulfilled(self.value); // 承前
          return result instanceof MyPromise? result.then(resolve, reject) : resolve(result); //启后
        }catch(err){
          reject(err)
        }
      }
      // 封装前一个promise失败时执行的函数
      let rejected = () => {
        try{
          const result = onReject(self.reason);
          return result instanceof MyPromise? result.then(resolve, reject) : reject(result);
        }catch(err){
          reject(err)
        }
      }

      switch(self.status){
        case PENDING: 
          self.onFulfilledCallbacks.push(fulfilled);
          self.onRejectedCallbacks.push(rejected);
          break;
        case FULFILLED:
          fulfilled();
          break;
        case REJECT:
          rejected();
          break;
      }
    })
   }

   // Promise.prototype.catch就是Promise.prototype.then(null, onRejected)的别名
   catch(onRejected){
     return this.then(null, onRejected);
   }

  static resolve(value){
    // 如果是promise实例,直接返回
    if(value instanceof MyPromise){
      return value;
    }else{
      // 如果不是promise实例,返回一个新的promise对象,状态为fulfilled
      return new MyPromise((resolve, reject) => resolve(value))
    }
  }
  static reject(reason){
    // Promise.reject方法的参数会原封不动地作为reject的参数
      return new MyPromise((resolve, reject) => reject(reason))
  }

  /**
   * Promise.all() 接受一个数组,返回一个promise对象
   *    所有的promise状态变为FULFILLED,返回的promise状态才变为FULFILLED。
   *     一个promise状态变为REJECTED,返回的promise状态就变为REJECTED。
   *    数组成员不一定都是promise,需要使用Promise.resolve()处理。
   */
  static all(promiseArr){
    const len = promiseArr.length;
    const values = new Array(len);

    let count = 0; // 记录已经成功的promise个数
    return new MyPromise((resolve, reject) => {
      for(let i=0; i<len; i++){
        // Promise.resolve()处理,确保每一个都是promise实例
        MyPromise.resolve(promiseArr[i]).then(
          val => {
            values[i] = val;
            count++;
            if(count === len) resolve(values); // 如果全部执行完,改变promise的状态为FulFilled
          },
          err => {
            reject(err)
          }
        )
      }
    })
  }
  static race(promiseArr){
    return new MyPromise((resolve, reject) => {
      promiseArr.forEach(item => {
        MyPromise,resolve(item).then(
          val => resolve(val),
          err => reject(err)
        )
      })
    })
  }
 }