手写Promise(二)

之前的部分可以看上一篇手写Promise(一)

catch和finally

我们经常遇到无论Promise最后状态如何都需要进行某些操作的情况。这时候就需要使用finally,因为finally方法传入的回调并不关心当前Promise的状态和结果,也不会改变返回的Promise的状态和结果,所以一定不要用then(onSettled, onSettled)来实现。

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

      finally(onSettled) {
        if (typeof onSettled !== "function") {
          return this.then();
        }
        return this.then(
          (data) => {
            onSettled();
            return data;
          },
          (reason) => {
            onSettled();
            throw reason;
          }
        );
      }
静态方法resolve和reject

resolve需要分情况讨论:

  1. 如果参数就是一个ES6的Promise对象,那么resolve会直接返回这个对象。
  2. 如果参数是一个thenable对象(可以沿用之前的isPromise来判断),会先调用它的then方法,将其转成一个Promise对象返回
  3. 不满足1和2的,返回一个新的Promise对象,状态为fulfilled,值为传入的参数

reject只会返回一个新的Promise对象,状态为rejected,值为传入的参数

      static resolve(value) {
        if (value && value instanceof Promise) {
          return value;
        } else if (isPromise(value)) {
          return new Promise((resolve) => {
            value.then(resolve);
          });
        } else {
          return new Promise((resolve) => resolve(value));
        }
      }

      static reject(value) {
        return new Promise((resolve, reject) => reject(value));
      }
静态方法all,allSettled和race

实现之前先看一个简单的例子

    Promise.all([
      Promise.resolve(1),
      1,
      2,
    ]).then(
      (data) => {
        console.log("data: ", data);
      },
      (reason) => {
        console.log("reason: ", reason);
      }
    );

输出结果:

data: [1, 1, 2]

 所以不能直接调用then方法,而应该调用Promise.resolve()

      static all(promises) {
        return new Promise((resolve, reject) => {
          const results = [];
          const total = promises.length;
          if (total === 0) {
            resolve(results);
          }
          let count = 0;
          promises.forEach((promise, index) => {
            Promise.resolve(promise).then(
              (data) => {
                count++;
                results[index] = data;
                if (count === total) {
                  resolve(results);
                }
              },
              (reason) => {
                reject(reason);
              }
            );
          });
        });
      }

      static allSettled(promises) {
        return new Promise((resolve) => {
          const results = [];
          const total = promises.length;
          if (total === 0) {
            resolve(results);
          }
          let count = 0;
          promises.forEach((promise, index) => {
            Promise.resolve(promise)
              .then(
                (value) => {
                  results[index] = { status: "fulfilled", value };
                },
                (reason) => {
                  results[index] = { status: "rejected", reason };
                }
              )
              .finally(() => {
                count++;
                if (count === total) {
                  resolve(results);
                }
              });
          });
        });
      }

      static race(promises) {
        return new Promise((resolve, reject) => {
          for (const promise of promises) {
            Promise.resolve(promise).then(resolve, reject);
          }
        });
      }
第五版实现
    function isPromise(value) {
      return (
        !!value &&
        (typeof value === "object" || typeof value === "function") &&
        typeof value.then === "function"
      );
    }

    function queueMicrotaskPolyfill(callback) {
      let textNode = document.createTextNode("");
      let counter = 0;

      const observer = new MutationObserver(() => {
        callback();
        observer.disconnect();
      });

      observer.observe(textNode, { characterData: true });
      textNode.data = String(counter++);
    }

    class Promise {
      constructor(executor) {
        this.state = "pending";
        this.value = null;
        this.handlers = [];
        try {
          executor(this._resolve.bind(this), this._reject.bind(this));
        } catch (error) {
          console.error(error);
          this._reject(error);
        }
      }

      static resolve(value) {
        if (value && value instanceof Promise) {
          return value;
        } else if (isPromise(value)) {
          return new Promise((resolve) => {
            value.then(resolve);
          });
        } else {
          return new Promise((resolve) => resolve(value));
        }
      }

      static reject(value) {
        return new Promise((resolve, reject) => reject(value));
      }

      static all(promises) {
        return new Promise((resolve, reject) => {
          const results = [];
          const total = promises.length;
          if (total === 0) {
            resolve(results);
          }
          let count = 0;
          promises.forEach((promise, index) => {
            Promise.resolve(promise).then(
              (data) => {
                count++;
                results[index] = data;
                if (count === total) {
                  resolve(results);
                }
              },
              (reason) => {
                reject(reason);
              }
            );
          });
        });
      }

      static allSettled(promises) {
        return new Promise((resolve) => {
          const results = [];
          const total = promises.length;
          if (total === 0) {
            resolve(results);
          }
          let count = 0;
          promises.forEach((promise, index) => {
            Promise.resolve(promise)
              .then(
                (value) => {
                  results[index] = { status: "fulfilled", value };
                },
                (reason) => {
                  results[index] = { status: "rejected", reason };
                }
              )
              .finally(() => {
                count++;
                if (count === total) {
                  resolve(results);
                }
              });
          });
        });
      }

      static race(promises) {
        return new Promise((resolve, reject) => {
          for (const promise of promises) {
            Promise.resolve(promise).then(resolve, reject);
          }
        });
      }

      then(onFulfilled, onRejected) {
        return new Promise((resolve, reject) => {
          this._pushHandler(onFulfilled, onRejected, resolve, reject);
          this._executeHandlers();
        });
      }

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

      finally(onSettled) {
        if (typeof onSettled !== "function") {
          return this.then();
        }
        return this.then(
          (data) => {
            onSettled();
            return data;
          },
          (reason) => {
            onSettled();
            throw reason;
          }
        );
      }

      _changeState(newState, value) {
        if (this.state !== "pending") {
          return;
        }
        this.state = newState;
        this.value = value;
        this._executeHandlers();
      }

      _resolve(data) {
        if (isPromise(data)) {
          data.then.call(
            data,
            this._resolve.bind(this),
            this._reject.bind(this)
          );
          return;
        }
        this._changeState("fulfilled", data);
      }

      _reject(reason) {
        this._changeState("rejected", reason);
      }

      _pushHandler(onFulfilled, onRejected, resolve, reject) {
        this.handlers.push({
          onFulfilled: onFulfilled || null,
          onRejected: onRejected || null,
          resolve: resolve,
          reject: reject,
          handled: false,
        });
      }

      _executeHandlers() {
        if (this.state === "pending") {
          return;
        }
        this.handlers.forEach((handler) => this._handle(handler));
      }

      _handle(handler) {
        if (handler.handled === true) {
          return;
        }
        queueMicrotaskPolyfill(() => {
          try {
            let result;
            if (this.state === "fulfilled") {
              result =
                typeof handler.onFulfilled === "function"
                  ? handler.onFulfilled(this.value)
                  : this.value;
              handler.resolve(result);
            } else if (this.state === "rejected") {
              if (typeof handler.onRejected === "function") {
                result = handler.onRejected(this.value);
                handler.resolve(result);
              } else {
                handler.reject(this.value);
              }
            }
          } catch (error) {
            console.error(error);
            handler.reject(error);
          } finally {
            handler.handled = true;
          }
        });
      }
    }

  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值