Promise作用和实现

196 阅读3分钟

Promise 作用

  1. Promise 表示异步操作的最终结果,解决异步回调、多层函数嵌套、并发的问题。
  2. 弊端:早期 IE 浏览器不支持。
  3. Promise 是一个类,new Promise 实例化传入 resolve,reject 去执行成功回调或失败回调。
  4. Promise 中的 then 回调返回普通值会将结果传递到下一次 then 的回调中。

Promise 实现

  1. Promise 一个类,Promise 中会传入 executor 执行器,默认执行。

  2. Promise 中的三种状态,pendding,resolved,rejected,一旦改变不会再次触发改变。

  3. then 方法,onFulfilled 第一个参数成功的回调传成功的 value,onRejcted 第二个参数是失败的回调的 reason

    • onFulfilled onRejcted 都是可选参数,如果不是函数会被忽略;
    • 如果是函数,onFulfilled 必须在成功之后调用,value 作为函数的参数。onRejcted 必须在拒绝之后调用,reason 作为函数的参数。
    • 一定不能在被拒绝或成功之前调用
    • 一定不能被调用多次
    • ...
  4. 如果 new Promise 中发生异常也会执行失败态

  5. catch 方法实现

  6. promise 链式调用实现

  7. Promise.resolve,Promise.reject,Promise.all, Promise.finally

Promise 测试是否符合 A+ 规范

  • 全局安装: npm install promises-aplus-tests -g

  • 控制台执行命令: promises-aplus-tests ./promise.js

实现代码

promise.js文件:

const PENDDING = "PENDDING",
  FULFILLED = "FULFILLED",
  REJECTED = "REJECTED";

/**链式调用核心处理x p2的关系 */
const resolvePromise = (x, p2, resolve, reject) => {
  if (x === p2) return reject("type error"); // 如果x和p2引用同一个对象TypeError
  if ((typeof x === "object" && x != null) || typeof x === "function") {
    let called;
    /**捕获异常start */
    try {
      // 检测x上是否有then属性
      let then = x.then;
      if (typeof then === "function") {
        then.call(
          x,
          (y) => {
            if (called) return;
            called = true;
            resolvePromise(y, p2, resolve, reject);
          },
          (e) => {
            if (called) return;
            called = true;
            reject(e);
          }
        );
      } else {
        resolve(x); // 直接用x作为成功结果
      }
    } catch (error) {
      if (called) return;
      called = true;
      reject(error);
    }
    /**捕获异常end */
  } else {
    resolve(x); // x一定是一个普通值此时p2的promise变成成功态
  }
};
class Promise {
  constructor(executor) {
    this.status = PENDDING;
    this.value = undefined;
    this.reason = undefined;
    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      this.status = FULFILLED;
      this.value = value;
      this.onResolvedCallbacks.forEach((fn) => fn());
    };
    const reject = (reason) => {
      this.status = REJECTED;
      this.reason = reason;
      this.onRejectedCallbacks.forEach((fn) => fn());
    };

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }
  then(onFulfilled, onRejcted) {
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (v) => v;
    onRejcted =
      typeof onRejcted === "function"
        ? onRejcted
        : (err) => {
            throw err;
          };

    let p2 = new Promise((resolve, reject) => {
      /**链式调用 */
      if (this.status === FULFILLED) {
        setTimeout(() => {
          try {
            // 成功传入成功的原因
            let x = onFulfilled(this.value);
            resolvePromise(x, p2, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 1000);
      }
      if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            // 失败传入失败的原因
            let x = onRejcted(this.reason);
            resolvePromise(x, p2, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 1000);
      }
      if (this.status === PENDDING) {
        // 等待状态时将成功和失败的回调函数收集起来
        this.onResolvedCallbacks.push(() => {
          setTimeout(() => {
            try {
              // 成功传入成功的原因
              let x = onFulfilled(this.value);
              resolvePromise(x, p2, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 1000);
        });
        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              // 失败传入失败的原因
              let x = onRejcted(this.reason);
              resolvePromise(x, p2, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 1000);
        });
      }
      /**链式调用 */
    });
    return p2;
  }

  // catch方法实现就是then的第一个参数是null
  catch(onRejected) {
    return this.then(null, onRejected);
  }

  // static静态方法通过类调用
  static resolve(value) {
    return new Promise((resolve, reject) => {
      resolve(value); // 有等待效果
    });
  }

  // static静态方法通过类调用
  static reject(reason) {
    return new Promise((resolve, reject) => {
      reject(reason); // 不具备等待效果
    });
  }
}

/** promise-aplus-tests */
Promise.deferred = function () {
  let dfd = {};
  dfd.promise = new Promise((resolve, reject) => {
    dfd.resolve = resolve;
    dfd.reject = reject;
  });
  return dfd;
};

/** finally 无论如何都会被执行;应用场景:某些流程 无论成功或失败都执行。成功以外面为主失败走里面的。 */
Promise.prototype.finally = function (cb) {
  return this.then(
    (y) => {
      return Promise.resolve(cb()).then(() => y);
    },
    (r) => {
      Promise.resolve(cb()).then(() => {
        throw r;
      });
    }
  );
};

/** all 全成功才成功,有一个失败则进入失败。执行是有顺序的。 */
Promise.all = function (promises) {
  return new Promise((resolve, reject) => {
    const arr = [];
    let times = 0;
    const processResult = (i, val) => {
      arr[i] = val;
      if (++times === promises.length) {
        resolve(arr);
      }
    };
    for (let i = 0; i < promises.length; i++) {
      let val = promises[i];
      if (typeof val.then === "function") {
        val.then((v) => processResult(i, v), reject);
      } else {
        processResult(i, val);
      }
    }
  });
};

module.exports = Promise;

index.js文件:

/** 可以调各种Promise方法测试promise.js源码中的内容这里列举一二*/

const Promise = require('./promise');

const p = new Promise((resolve, reject) => {
    // resolve(1);
    reject();
});
p.finally(() => {
    console.log('怎么样都执行');
}).then(res => {
    console.log(res, 1);
}, err => {
    console.log(err, 2);
});

Promise.all([Promise.resolve(1), Promise.resolve(2), Promise.reject(3)]).then(res => {
    console.log(res, '==');
}, err => {
    console.log(err, '--');
})

控制台执行查看效果

执行命令:node index.js