ES6中的Promise实现原理

说明

由于手写实现Promise无法区别宏任务与微任务,因此这里的实现源码只是为了理解。

Promise规范要点

  • Promise是一个类,接收一个函数作为参数,该函数称为执行器,创建Promise对象时,执行器会立刻执行;
  • Promise有三种状态,分别为pending等待、fulfilled成功、rejected失败;其中pending会转换为fulfilled或者rejected,一旦状态更新,则无法再更新状态;
  • 执行器函数接收两个参数,分别为resolve函数和reject函数,只是用于更新Promise对象的状态,并可以将数据传递下去;reject的参数并不是错误,只有用throw语句才会抛出错误。抛出错误的时候,由执行器函数或回调函数内部的try-catch语句来捕获。由于我们的reject函数放在了catch语句里,因此then方法的rejected回调函数使用throw来向下传递数据。
  • then()方法内部需要判断状态,状态成功则调用onFulfilled函数,状态失败则调用onRejected函数。
  • 异步情况的处理,需要存储then方法内部的回调函数,在异步任务结束时,调用resolve或reject后,同时调用相应的回调函数
// 定义状态常量,在编辑器中可以得到代码提示信息;
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
  constructor(executor) {
    // try-catch捕获执行器异常
    try {
      executor(this.resolve, this.reject);
    } catch(e) {
      this.reject(e);
    }
  }
  // 定义实例属性,用于表示Promise的状态
  _status = PENDING;
  // 成功之后的值
  _value = undefined;
  // 失败之后的值
  _err = undefined;
  // 用于存储成功回调函数的队列,实现给同一个Promise用then()注册多个回调函数
  onSuccess = [];
  // 用于存储失败回调函数的队列,实现给同一个Promise用then()注册多个回调函数
  onFail = [];
  // 之所以定义为箭头函数,是为了在使用resolve()调用时,内部的this指向MyPromise的实例
  resolve = (value) => {
    // 判断状态,如果不是PENDING,则返回;
    if(this._status !== PENDING) return;
    // 更新状态
    this._status = FULFILLED;
    // 保存value值
    this._value = value;
    // 判断成功回调是否存在,如果存在,则调用
    // this.onSuccess && this.onSuccess(this._value);
    while(this.onSuccess.length) {
      this.onSuccess.shift()();
    }
  }
  reject = (err) => {
    // 判断状态,如果不是PENDING,则返回;
    if(this._status !== PENDING) return;
    // 更新状态
	this._status = REJECTED;
	// 保存err
	this._err = err;
	// 判断失败回调是否存在,如果存在,则调用
	// this.onFail && this.onFail(this._err);
	while(this.onFail.length) {
      this.onFail.shift()();
    }
  }
  // 实现then方法
  then(successCallback, failCallback) {
    // 解决then()方法可选参数的问题;
    successCallback = successCallback ? successCallback: value => value;
    // 用throw语句将异常传递下去,throw语句用来抛出异常,可以将throw关键字后面表达式的值抛出
    failCallback = failCallback ? failCallback: err => { throw err; }
    // 创建一个Promise对象并返回,实现链式调用;
    let my_promise = new MyPromise((resolve, reject) => {
	  // 判断状态
      if(this._status === FULFILLED) {
        setTimeout(() => {
          // 捕获回调函数中的异常
          try {
            // 创建变量来接收成功回调函数的返回值;
            let x = successCallback(this._value);
            // 判断x值是否是Promise对象,如果是普通值,则直接resolve或reject
            // 否则需要查看Promise对象的值,再调用resolve或reject
            // 调用resolvePromise(),将x的值传递出去;
            // 由于三种状态下都需要用到这个函数,所以这里的resolvePromise()方法抽象为公共函数
            // 传入my_promise是为了对比my_promise与x是否相同,相同则表示出现Promise循环调用,需要抛出异常
            // my_promise对象无法在同步的情况下拿到
            // 因此将整个代码放到setTimeout()中来获取my_promise对象
            resolvePromise(my_promise, x, resolve, reject);
          } catch(e) {
            reject(e);
          }
        }, 0);
      } else if(this._status === REJECTED) {
          setTimeout(() => {
            try {
              let x = failCallback(this._err);
              resolvePromise(my_promise, x, resolve, reject);
            } catch(e) {
              reject(e);
            }
          }, 0);
      } else {
        // 处理异步情况,此时为PENDING状态,就将成功状态和失败状态的回调函数存储起来
        this.onSuccess.push(() => {
		  setTimeout(() => {
            try {
              let x = successCallback(this._value);
            } catch(e) {
              reject(e);
            }
          }, 0);
        });
        this.onFail.push(() => {
		  setTimeout(() => {
            try {
              let x = failCallback(this._value);
            } catch(e) {
              reject(e);
            }
          }, 0);
        });
      }
    });
   	return my_promise;
  }
  // 定义静态方法all()
 static all(arr) {
   // 声明一个数组,用来存储arr中所有操作的结果
   let result = [];
   // 声明一个变量index,用来判断是否所有异步操作都已完成,如果异步操作未完成,index值小于arr.length
   let index = 0;
   return new MyPromise((resolve, reject) => {
     // 声明addData函数,用于将操作的结果存储到result数组
     function addData(key, value) {
       result[key] = value;
       index ++;
       if(index === arr.length) {
         resolve(result);
       }
     }
     for(let i = 0; i < arr.length; i ++) {
       let current = arr[i];
       if(current instanceof MyPromise) {
         // 当前arr元素为Promise对象
         current.then((value) => {
           addData(value);
         }, (err) => {
           reject(err);
         })
       } else {
         // 当前arr元素不是Promise对象
         addData(i, arr[i]);
       }
     }
   })
 }
 // 定义静态方法resolve
 static resolve(value) {
   // 如果传入的value是Promise对象,则原样返回,否则返回新的Promise对象,将value传递
   if(value instanceof MyPromise) {
     return value;
   } else {
     return new MyPromise((resolve) => {
       resolve(value);
     })
   }
 }
 // 定义实例finally方法,不管Promise对象状态如何,finally的回调函数一定会执行
 finally(callback) {
   // 返回一个Promise对象
   return this.then((value) => {
     return MyPromise.resolve(callback()).then(() => value);
   }, (err) => {
     return MyPromise.resolve(callback()).then(() => { throw err; });
   })
 }
 // 定义实例catch方法
 catch(failCallback) {
   // 调用then方法,只传递onRejected状态的回调即可
   return this.then(undefined, failCallback);
 }
}
function resolvePromise(my_promise, x, resolve, reject) {
  if(my_promise === x) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
  }
  if(x instanceof MyPromise) {
    // x是Promise对象,则调用then方法查看值,并利用resolve或reject传递
    /* x.then((value) => {
      resolve(value)
    }, (err) => {
      reject(err);
    }); */
    x.then(resolve, reject);
  } else {
    resolve(x);
  }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值