Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Promise 手动实现 #2

Open
SuperTapir opened this issue Apr 5, 2020 · 0 comments
Open

Promise 手动实现 #2

SuperTapir opened this issue Apr 5, 2020 · 0 comments

Comments

@SuperTapir
Copy link
Owner

SuperTapir commented Apr 5, 2020

Promise/A+ 规范概览

1. Promise 是一个状态机,状态变化不可逆

pending ———>  Fulfilled
   |
   |———————>  Rejected

2. Promise 有 then 方法,可被调用多次,返回 Promise 对象

3. 支持链式调用,内部记录 value,用来记录上次计算的结果值,如果报错,说明保存的是异常

实现步骤

实现 Promise 的基本框架

实现了 Promise 的构造函数

class MyPromise {
  constructor(executor) {
    this.value = null;
    this.reason = null;
    const resolve = value => {
      this.value = value;
    };

    const reject = reason => {
      this.reason = reason;
    };

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }
}

增加状态机

将 Promise 的三种状态引入实现,并且在正确的时机改变状态

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
  constructor(executor) {
    this.value = null;
    this.reason = null;
    this.state = PENDING;

    const resolve = value => {
      if (this.state === PENDING) {
        this.value = value;
        this.state = FULFILLED;
      }
    };

    const reject = reason => {
      if (this.state === PENDING) {
        this.reason = reason;
        this.state = REJECTED;
      }
    };

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }
}

实现 then 方法

then 函数,需要在 Promise fulfilled 的时候调用成功回调, rejected 时调用失败回调

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
  constructor(executor) {
    this.value = null;
    this.reason = null;
    this.state = PENDING;

    const resolve = (value) => {
      if (this.state === PENDING) {
        this.value = value;
        this.state = FULFILLED;
      }
    };

    const reject = (reason) => {
      if (this.state === PENDING) {
        this.reason = reason;
        this.state = REJECTED;
      }
    };

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  then(onFulfilled, onRejected) {
    // 判别传入的值,是否为函数,如果不是,需要给予缺省值
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (_) => _;
    onRejected =
      typeof onRejected === 'function'
        ? onRejected
        : (_) => {
            throw _;
          };

    if (this.state === FULFILLED) {
      onFulfilled(this.value);
    }
    if (this.state === REJECTED) {
      onRejected(this.reason);
    }
  }
}

实现异步调用

通过两个数组保存 then 方法传入的函数,并且在 resolve 或 reject 的时候调用数组内的方法

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
  constructor(executor) {
    this.value = null;
    this.reason = null;
    this.state = PENDING;

    this.onFulfilledCbs = [];
    this.onRejectedCbs = [];

    const resolve = (value) => {
      if (this.state === PENDING) {
        this.value = value;
        this.state = FULFILLED;
        this.onFulfilledCbs.forEach((fn) => fn());
      }
    };

    const reject = (reason) => {
      if (this.state === PENDING) {
        this.reason = reason;
        this.state = REJECTED;
        this.onRejectedCbs.forEach((fn) => fn());
      }
    };

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  then(onFulfilled, onRejected) {
    // 判别传入的值,是否为函数,如果不是,需要给予缺省值
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (_) => _;
    onRejected =
      typeof onRejected === 'function'
        ? onRejected
        : (_) => {
            throw _;
          };

    this.onFulfilledCbs.push(() => onFulfilled(this.value));
    this.onRejectedCbs.push(() => onRejected(this.value));
  }
}

实现 then 基本的链式调用

Then 方法需要返回一个 Promise

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
  constructor(executor) {
    this.value = null;
    this.reason = null;
    this.state = PENDING;

    this.onFulfilledCbs = [];
    this.onRejectedCbs = [];

    const resolve = (value) => {
      if (this.state === PENDING) {
        this.value = value;
        this.state = FULFILLED;
        this.onFulfilledCbs.forEach((fn) => fn());
      }
    };

    const reject = (reason) => {
      if (this.state === PENDING) {
        this.reason = reason;
        this.state = REJECTED;
        this.onRejectedCbs.forEach((fn) => fn());
      }
    };

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  then(onFulfilled, onRejected) {
    // 判别传入的值,是否为函数,如果不是,需要给予缺省值
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (_) => _;
    onRejected =
      typeof onRejected === 'function'
        ? onRejected
        : (_) => {
            throw _;
          };

    return new MyPromise((resolve, reject) => {
      const fulfilledPromise = () => {
        setTimeout(() => {
          try {
            resolve(onFulfilled(this.value));
          } catch (error) {
            reject(error);
          }
        });
      };
      const rejectPromise = () => {
        setTimeout(() => {
          try {
            reject(onRejected(this.reason));
          } catch (error) {
            reject(error);
          }
        });
      };
      if (this.state === PENDING) {
        this.onFulfilledCbs.push(fulfilledPromise);
        this.onRejectedCbs.push(rejectPromise);
      } else if (this.state === FULFILLED) {
        fulfilledPromise();
      } else if (this.state === REJECTED) {
        rejectPromise();
      }
    });
  }
}

到这里,其实 then 方法还有一个很重要的点没有实现,就是在then方法里,是可以通过回调函数 return 一个 Promise 值的,而这时,这个 Promise 会被展开并作为当前链式调用的决议值

实现 then 对于 Promise 值的处理

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
  constructor(executor) {
    this.value = null;
    this.reason = null;
    this.state = PENDING;

    this.onFulfilledCbs = [];
    this.onRejectedCbs = [];

    const resolve = (value) => {
      if (this.state === PENDING) {
        this.value = value;
        this.state = FULFILLED;
        this.onFulfilledCbs.forEach((fn) => fn());
      }
    };

    const reject = (reason) => {
      if (this.state === PENDING) {
        this.reason = reason;
        this.state = REJECTED;
        this.onRejectedCbs.forEach((fn) => fn());
      }
    };

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  then(onFulfilled, onRejected) {
    // 判别传入的值,是否为函数,如果不是,需要给予缺省值
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (_) => _;
    onRejected =
      typeof onRejected === 'function'
        ? onRejected
        : (_) => {
            throw _;
          };

    const nextPromise = new MyPromise((resolve, reject) => {
      const fulfilledPromise = () => {
        setTimeout(() => {
          try {
            resolvePromise(nextPromise, onFulfilled(this.value), resolve, reject);
          } catch (error) {
            reject(error);
          }
        });
      };
      const rejectPromise = () => {
        setTimeout(() => {
          try {
            resolvePromise(nextPromise, onRejected(this.reason), resolve, reject);
          } catch (error) {
            reject(error);
          }
        });
      };
      if (this.state === PENDING) {
        this.onFulfilledCbs.push(fulfilledPromise);
        this.onRejectedCbs.push(rejectPromise);
      } else if (this.state === FULFILLED) {
        fulfilledPromise();
      } else if (this.state === REJECTED) {
        rejectPromise();
      }
    });

    return nextPromise;
  }
}

function resolvePromise(promise, value, resolve, reject) {
  // 防止循环
  if (promise === value) {
    reject(new TypeError('Chaining cycle'));
  }

  // 判断 value 是否为一个 thenable 值
  if (
    value !== null &&
    (typeof value === 'object' || typeof value === 'function') &&
    typeof value.then === 'function'
  ) {
    try {
      value.then(
        (v) => {
          resolvePromise(promise, v, resolve, reject);
        },
        (err) => {
          reject(err);
        }
      );
    } catch (error) {
      reject(error);
    }
  } else {
    resolve(value);
  }
}

实现 catch 的异常处理

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
  constructor(executor) {
    this.value = null;
    this.reason = null;
    this.state = PENDING;

    this.onFulfilledCbs = [];
    this.onRejectedCbs = [];

    const resolve = (value) => {
      if (this.state === PENDING) {
        this.value = value;
        this.state = FULFILLED;
        this.onFulfilledCbs.forEach((fn) => fn());
      }
    };

    const reject = (reason) => {
      if (this.state === PENDING) {
        this.reason = reason;
        this.state = REJECTED;
        this.onRejectedCbs.forEach((fn) => fn());
      }
    };

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  then(onFulfilled, onRejected) {
    // 判别传入的值,是否为函数,如果不是,需要给予缺省值
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (_) => _;
    onRejected =
      typeof onRejected === 'function'
        ? onRejected
        : (_) => {
            throw _;
          };

    const nextPromise = new MyPromise((resolve, reject) => {
      const fulfilledPromise = () => {
        setTimeout(() => {
          try {
            resolvePromise(nextPromise, onFulfilled(this.value), resolve, reject);
          } catch (error) {
            reject(error);
          }
        });
      };
      const rejectPromise = () => {
        setTimeout(() => {
          try {
            resolvePromise(nextPromise, onRejected(this.reason), resolve, reject);
          } catch (error) {
            reject(error);
          }
        });
      };
      if (this.state === PENDING) {
        this.onFulfilledCbs.push(fulfilledPromise);
        this.onRejectedCbs.push(rejectPromise);
      } else if (this.state === FULFILLED) {
        fulfilledPromise();
      } else if (this.state === REJECTED) {
        rejectPromise();
      }
    });

    return nextPromise;
  }

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

function resolvePromise(promise, value, resolve, reject) {
  // 防止循环
  if (promise === value) {
    reject(new TypeError('Chaining cycle'));
  }

  // 判断 value 是否为一个 thenable 值
  if (
    value !== null &&
    (typeof value === 'object' || typeof value === 'function') &&
    typeof value.then === 'function'
  ) {
    try {
      value.then(
        (v) => {
          resolvePromise(promise, v, resolve, reject);
        },
        (err) => {
          reject(err);
        }
      );
    } catch (error) {
      reject(error);
    }
  } else {
    resolve(value);
  }
}

总结

根据上述步骤,大致完成了 Promise 的一个实现,经过我的测试大部分情况应该是都能通过的。

我和真正的 Promise/A+ 规范进行了比对,又参考了很多大神的实现方式,了解到想要真正做到完全的符合规范是需要做非常多判断的,需要做大量的工作,感觉理解规范的意图和其作用非常困难,我还是准备偷个懒,我已经大致了解了如何去实现一个 Promise, 最后只剩一些小细节了,这部分细节准备先放一放,等下次有空好好参照规范写一下

参考资料

#前端

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant