关于javascript:javascript-Promise底层实现

5次阅读

共计 4515 个字符,预计需要花费 12 分钟才能阅读完成。

class Promise {constructor(handle) {if (typeof handle !== "function") {throw new Error("promise must accept a function as a parameter");
    }

    // 定义三种状态配置
    this.STATUS = {
      PENDING: "pending",
      FULFILLED: "fulfilled",
      REJECTED: "rejected"
    };

    // 初始化状态
    this._status = this.STATUS.PENDING;
    // 初始化值
    this._value = undefined;

    // 胜利状态须要执行的工作队列
    this._fulfilledQueues = [];
    // 失败状态须要执行的工作队列
    this._rejectedQueues = [];

    // 执行 handle
    try {handle(this._resolve.bind(this), this._reject.bind(this));
    } catch (err) {this._reject(err);
    }
  }

  // Object.prototype.toString.call(promiseObj) === "[object Promise]"
  get [Symbol.toStringTag](){return "Promise"}

  _runMicroTask(callback) {
    // 应用浏览器 MutationObserver WEB.API 实现 then 办法的微工作机制
    let count = 0;
    const observer = new MutationObserver(callback);
    // 创立文本节点,节约资源
    const textNode = document.createTextNode(String(count));
    observer.observe(textNode, {
      // 当文本扭转时触发回调
      characterData: true
    });
    // 扭转文本,回调 callback 触发
    textNode.data = String(++count);
  }

  _resolve(val) {if (this._status !== this.STATUS.PENDING) return;
    const onFulfilled = v => {
      this._status = this.STATUS.FULFILLED;
      this._value = v;
      let cb;
      while ((cb = this._fulfilledQueues.shift())) {cb(v);
      }
    };
    const onRejected = err => {
      this._status = this.STATUS.REJECTED;
      this._value = err;
      let cb;
      while ((cb = this._rejectedQueues.shift())) {cb(err);
      }
    };

    // 顺次执行胜利队列中的函数,并清空队列
    const run = () => {if (val instanceof Promise) {
        // 如果入参是一个 Promise,则 val 的 status 及 value 值决定了以后 promise 实例的 status 和 value 值
        val.then(onFulfilled, onRejected);
      } else {onFulfilled(val);
      }
    };

    this._runMicroTask(run);
  }

  _reject(val) {if (this._status !== this.STATUS.PENDING) return;
    // 顺次执行失败队列中的函数,并清空队列
    const run = () => {
      this._status = this.STATUS.REJECTED;
      this._value = val;
      let cb;
      while ((cb = this._rejectedQueues.shift())) {cb(val);
      }
    };

    this._runMicroTask(run);
  }

  then(onFulfilled, onRejected) {
    // then 反对链式调用,返回一个新的 promise
    return new Promise((resolve, reject) => {
      const handleResolve = value => {
        try {if (typeof onFulfilled !== "function") {
            // 如果 onFulfilled 不是函数,则间接返回以后 promise 的 value 值
            resolve(value);
          } else {const res = onFulfilled(value);
            // Promise.prototype 是否存在于 res 的原型链上,是则阐明 res 是 Promise 实例
            if (res instanceof Promise) {res.then(resolve, reject);
            } else {resolve(res);
            }
          }
        } catch (err) {reject(err);
        }
      };

      const handleReject = value => {
        try {if (typeof onRejected !== "function") {
            // 如果 onFulfilled 不是函数,则间接返回以后 promise 的 value 值
            resolve(value);
          } else {const res = onRejected(value);
            if (res instanceof Promise) {res.then(resolve, reject);
            } else {resolve(res);
            }
          }
        } catch (err) {reject(err);
        }
      };

      switch (this._status) {
        case this.STATUS.PENDING:
          this._fulfilledQueues.push(handleResolve);
          this._rejectedQueues.push(handleReject);
          break;
        case this.STATUS.FULFILLED:
          handleResolve(this._value);
          break;
        case this.STATUS.REJECTED:
          handleReject(this._value);
          break;
      }
    });
  }

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

  // 增加动态 resolve 办法
  static resolve(value) {
    // 如果参数是 MyPromise 实例,间接返回这个实例
    if (value instanceof Promise) return value;
    return new Promise(resolve => resolve(value));
  }

  // 增加动态 reject 办法
  static reject(err) {return new Promise((resolve, reject) => reject(err));
  }

  // 增加动态 all 办法, 所有 promise 入参状态产生扭转后才扭转状态
  static all(list) {return new Promise((resolve, reject) => {
      const length = list.length;
      let count = 0;
      let values = [];
      // // entries 返回数组的键值对 [[index, value]...]
      // for (let [i, p] of list.entries()) {
      //
      // }
      for (let i = 0; i < length; i++) {const promise = list[i];
        promise.then(
          res => {
            // promise 有可能异步执行 resolve,不能用 push
            values[i] = res;
            count++;
            if (count === length) {resolve(values);
            }
          },
          err => {
            // 只有子元素 promise 中有任何一个 reject,则返回的 promise rejected
            reject(err);
          }
        );
      }
    });
  }

  // 增加动态 race 办法
  static race(list) {return new Promise((resolve, reject) => {for (let p of list) {
        // 只有有一个实例率先扭转状态,新的 MyPromise 的状态就跟着扭转
        this.resolve(p).then(
          res => {resolve(res);
          },
          err => {reject(err);
          }
        );
      }
    });
  }

  /*finally() 办法返回一个 Promise。在 promise 完结时,无论后果是 fulfilled 或者是 rejected,都会执行指定的回调函数。这为在 Promise 是否胜利实现后都须要执行的代码提供了一种形式。这防止了同样的语句须要在 then() 和 catch() 中各写一次的状况。*/
  finally(handle) {
    return this.then(
      value => {handle();
        return Promise.resolve(value);
      },
      err => {handle();
        return Promise.reject(err);
      }
    );
  }
}

// console.log(Promise.resolve)
// // new Promise((res, rej) => setTimeout(() => rej(777)), 1000)
// //     .then(res => console.log({res}), err => console.log(1, err))
// //     .then(res => console.log({res}), err => console.log(2, err))
//
// console.log(Promise.resolve(Promise.resolve(222)))
//
//
// // new Promise((res, rej) => rej(666))
// //     .then(res => console.log({res}), err => new Promise(res => setTimeout(() => res (123),3000)))
// //     .then(res => console.log({then2: res}), err => console.log(2, err))
//
// new Promise((res, rej) => res(new Promise((r, err) => err(857))))
//     .then(null, e => new Promise(res => res(111)))
//     .then(a => console.log({a})).catch(cat => console.log({cat}))

console.log("哇哈哈");
setTimeout(() => {console.log("setTimeout");
}, 0);

new Promise((res, rej) => {rej(111);
})
  .finally(() => {console.log("执行 finally");
  })
  .then(null, err => console.log({ err}));

console.log("666");
if (window) {console.log("you dinwow");
}
正文完
 0