实现 Promise - 翻译

  1. 状态机
  2. 状态转变
  3. 搭建 Promise
  4. 观察
  5. 实现. then

更好地理解 Promise

英文原文链接

状态机

由于 promise 只是一个状态机,我们应该首先引入我们后面需要的状态信息。

var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise() {
  // 状态可以是 PENDING, FULFILLED or REJECTED
  let state = PENDING;

  // 在状态变为 FULFILLED or REJECTED 后,存储 value 或者 error 
  let value = null;

  // 通过调用 .then 或者 .done,存储成功或失败的 handlers 
  var handlers = [];
}

状态转变

var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise() {
  // 状态可以是 PENDING, FULFILLED or REJECTED
  let state = PENDING;

  // 在状态变为 FULFILLED or REJECTED 后,存储 value 或者 error 
  let value = null;

  // 通过调用 .then 或者 .done,存储成功或失败的 handlers 
  var handlers = [];

  function fulfill(result) {
    state = FULFILLED;
    value = result;
  }

  function reject(error) {
    state = REJECTED;
    value = error;
  }
}

这为我们提供了基本的低级转换,但让我们考虑一个额外的、更高级别的转换,resolve

var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise() {
  // store state which can be PENDING, FULFILLED or REJECTED
  var state = PENDING;

  // store value once FULFILLED or REJECTED
  var value = null;

  // store sucess & failure handlers
  var handlers = [];

  function fulfill(result) {
    state = FULFILLED;
    value = result;
  }

  function reject(error) {
    state = REJECTED;
    value = error;
  }

  function resolve(result) {
    try {
      let then = getThen(result);
      if (then) {
        doResolve(then.bind(result), resolve, reject)
        return
      }
      // then 是 null 时调用 fulfill,即 result 是纯值时调用
      fulfill(result);
    } catch (e) {
      reject(e);
    }
  }
}

注意,resolve 函数接收一个 promise 对象或者其他非 promise 对象。接收 promise 对象时,会等待此对象完成状态转换。
一个 promise 是不能通过另一个 promise 完成状态转换到 fulfilled,此时我们将暴露的是这个 resolve 函数,而不是内部的 fulfill 函数,我们使用了辅助方法:

  • getThen 方法
    /**
    * 检查 value 是否是 Promise ,如果是, 返回 value.then.
    *
    * @param Promise 或其他任何值
    * @return 函数或者 null
    */
    function getThen(value) {
    var t = typeof value;
    if (value && (t === 'object' || t === 'function')) {
      var then = value.then;
      if (typeof then === 'function') {
        return then;
      }
    }
    return null;
    }
  • doResolve 方法
    /**
    * 接收一个潜在的错误行为的 resolver 函数,并确保 onFulfilled 和 onRejected 只会被调用一次
    *
    * 此方法没有异步安全性
    *
    * @param {Function} fn : 一个 resolver 函数,可能不可信的
    * @param {Function} 函数 onFulfilled
    * @param {Function} 函数 onRejected
    */
    function doResolve(fn, onFulfilled, onRejected) {
    var done = false;
    try {
      fn(function (value) {
        if (done) return
        done = true
        onFulfilled(value)
      }, function (reason) {
        if (done) return
        done = true
        onRejected(reason)
      })  // fn 函数执行结束
    } catch (ex) {
      if (done) return
      done = true
      onRejected(ex)
    }
    }

    搭建 Promise

var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise(fn) {
  // store state which can be PENDING, FULFILLED or REJECTED
  var state = PENDING;

  // store value once FULFILLED or REJECTED
  var value = null;

  // store sucess & failure handlers
  var handlers = [];

  function fulfill(result) {
    state = FULFILLED;
    value = result;
  }

  function reject(error) {
    state = REJECTED;
    value = error;
  }

  function resolve(result) {
    try {
      var then = getThen(result);
      if (then) {
        doResolve(then.bind(result), resolve, reject)
        return
      }
      fulfill(result);
    } catch (e) {
      reject(e);
    }
  }

  doResolve(fn, resolve, reject);
}

我们多次使用 doResolve,因为我们有多个不可信任的 resolver。fn 被允许多次调用 resolvereject,即使抛出了异常。我们有责任确保承诺只变为 resolved 或 rejected 一次,然后永远不会再转换到不同的状态。

观察

状态机已经完整了,但是我们不能观察或者改变状态机,我们的究极目标是实现 .then 方法,但是这里先实现一个比 .then 简单地 .done 方法。
.done(onFulfilled, onRejected) 方法:

  1. 只会被 onFulfilled 或者 onRejected 调用
  2. 只会被调用一次
  3. 直到下一个滴答声(即在 .done 方法返回之后)才会被调用
  4. 无论 rpomsie 在我们调用 .done 之前还是之后 resolved 了,.done 都会被调用
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise(fn) {
  // store state which can be PENDING, FULFILLED or REJECTED
  var state = PENDING;

  // store value once FULFILLED or REJECTED
  var value = null;

  // store sucess & failure handlers
  var handlers = [];

  function fulfill(result) {
    state = FULFILLED;
    value = result;
  }

  function reject(error) {
    state = REJECTED;
    value = error;
  }

  function resolve(result) {
    try {
      var then = getThen(result);
      if (then) {
        doResolve(then.bind(result), resolve, reject)
        return
      }
      fulfill(result);
    } catch (e) {
      reject(e);
    }
  }

function handle(handler) {
    if (state === PENDING) {
      handlers.push(handler);
    } else {
      if (state === FULFILLED &&
        typeof handler.onFulfilled === 'function') {
        handler.onFulfilled(value);
      }
      if (state === REJECTED &&
        typeof handler.onRejected === 'function') {
        handler.onRejected(value);
      }
    }
  }

  this.done = function (onFulfilled, onRejected) {
    // ensure we are always asynchronous
    setTimeout(function () {
      handle({
        onFulfilled: onFulfilled,
        onRejected: onRejected
      });
    }, 0);
  } 

  doResolve(fn, resolve, reject);
}

实现. then

then 需要返回一个 Promise 对象

this.then = function (onFulfilled, onRejected) {
  var self = this;
  return new Promise(function (resolve, reject) {
    return self.done(function (result) {
      if (typeof onFulfilled === 'function') {
        try {
          return resolve(onFulfilled(result));
        } catch (ex) {
          return reject(ex);
        }
      } else {
        return resolve(result);
      }
    }, function (error) {
      if (typeof onRejected === 'function') {
        try {
          return resolve(onRejected(error));
        } catch (ex) {
          return reject(ex);
        }
      } else {
        return reject(error);
      }
    });
  });
}

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论。
我的空间