2

1.Promise的含义

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

Promise对象有以下两个特点。

(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。

2.Promise的标准

Promise/A+规范(英语原版)
Promise/A+规范中文版
以下是底层实现全部内容:
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");
}
// 安装promise测试插件
npm i promises-aplus-tests -D
// package.json文件配置下脚本执行部分
"scripts": {
    "test": "promises-aplus-tests myPromise.js(填入自己开发的promise的名字)"
  },
class MyPromise {...}
MyPromise.defer = MyPromise.deferred = function () {
  let dfd = {};
  dfd.promise = new MyPromise((resolve, reject) => {
    dfd.resolve = resolve;
    dfd.reject = reject;
  });
  return dfd;
};
module.exports = MyPromise;

使用命令 npm run test 测试promise合规性,会打印出大量的信息


任天镗
12 声望2 粉丝