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

动手写一个符合promises-aplus-tests测试的promise库 #11

Closed
sevenCon opened this issue Aug 18, 2019 · 0 comments
Closed

动手写一个符合promises-aplus-tests测试的promise库 #11

sevenCon opened this issue Aug 18, 2019 · 0 comments
Labels

Comments

@sevenCon
Copy link
Owner

前言

动手写一写平时用到的Promise库, 早些时候,早就有动手写一写念头了, 如果真要动手写一个通过promise-aplus-tests的Promise库, 还是得动动心思的,里面有很多细节, 需要花很多心思去理解里面的test-case, 这部分的东西在官网是没有的.

promise的原理也不难,就是在then的时候,收集回调函数的依赖. 在resolve, 或者reject被调用的时候, 去一个接一个的调用then收集的回调函数.

流程图

image

简单的promise

const PENDING = 'pending';
const RESOLVED = 'resolved';
const REJECTED = 'rejected';

function Promise(callback) {
  this.value = '';
  this.reason = '';
  this.onRejectedCallbacks = [];
  this.onResolveCallbaccks = [];
  this.status = PENDING;
  let self = this;

  function resolve(value) {
    if (self.status == PENDING) {
      self.status = RESOLVED;
      self.value = value;
      self.onResolveCallbaccks.forEach(fn => {
        fn();
      });
    }
  }
  function reject(reason) {
    if (self.status == PENDING) {
      self.reason = reason;
      self.status = REJECTED;
      self.onRejectedCallbacks.forEach(fn => {
        fn();
      });
    }
  }
  callback(resolve, reject);
}

function resolvePromise(promise2, x, resolve, reject) {
  if ((typeof x == 'object' && x !== null) || typeof x == 'function') {
    let then = x.then;
    if (typeof then === 'function') {
      then.call(
        x,
        v => {
          resolvePromise(promise2, v, resolve, reject);
        },
        r => {
          reject(r);
        }
      );
    } else {
      resolve(x);
    }
  } else {
    resolve(x);
  }
}

Promise.prototype.then = function(onFulfilled, onRejected) {
  let self = this;
  let promise2 = new Promise(function(resolve, reject) {
    if (self.status == RESOLVED) {
      setTimeout(function() {
        let x = onFulfilled(self.value);
        resolvePromise(promise2, x, resolve, reject);
      });
    }
    if (self.status == REJECTED) {
      setTimeout(function() {
        let x = onRejected(self.reason);
        resolvePromise(promise2, x, resolve, reject);
      });
    }
    if (self.status == PENDING) {
      self.onResolveCallbaccks.push(function() {
        setTimeout(function() {
          let x = onFulfilled(self.value);
          resolvePromise(promise2, x, resolve, reject);
        });
      });

      self.onRejectedCallbacks.push(function() {
        setTimeout(function() {
          let x = onRejected(self.reason);
          resolvePromise(promise2, x, resolve, reject);
        });
      });
    }
  });

  return promise2;
};

module.exports = Promise;

image

以上的主流程是可以简单的运用的, 但是对于通过promises-aplus-tests的, 还需要检验很多的判断流程

  • 必要的try...catch, 在then函数的,构造函数的回调, 必须添加try...catch
  • resolve函数有可能返回一个promise
  • Promisecatch函数, 同样需要返回一个promise
  • then 函数的参数的缺省值, 需要返回下一个promise
  • resolvePromisex.then不可获取多次, 因为可能被getter挟持, 直接返回Error

以上是一个基本的注意事项, 但是还有许许多多的要点, 需要再执行的时候去看test-case的代码, 才知晓怎么改.
此外还需要了解一下Promises/A+规范 的详情.
本人写了一个完整版的Promise在promise-demo

参考

https://promisesaplus.com/#point-21
本文的github地址在动手写一个符合promises-aplus-tests测试的promise库, 如有侵权或其他问题,请issue留言, 感谢

@sevenCon sevenCon added the js label Aug 18, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant