从状态机的角度加深明白并完成Promise

这篇文章内容主要来自一篇stack Overflow高票答案

声明:此Promise的完成仅仅是为了加深本人对其的明白,和A+范例有些相差,然则的确是如今看过一切promise代码中最美丽,思绪比较清楚的一个。
文章不会特地协助读者温习Promise基础操纵。

状况机

Promise实在本质上就是一个状况机,所以起首我们形貌一个静态的状况机,就像下边如许

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

function Promise() {
  // 存储的状况是上边的三个:实行中,已完成,已谢绝
  var state = PENDING;

  // 存储异步效果或许异步毛病音讯
  var value = null;

  // 负责处置惩罚半途到场的处置惩罚函数
  var handlers = [];
}

状况转变

完成了基础的状况机定义,接下来的题目就是完成“状况转变”这个行动的完成:

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

function Promise() {
  // 存储三个状况
  var state = PENDING;

  // 一旦涌现状况的转变,异步效果就会被存到这个处所
  var value = null;

  // 存储胜利或许失利的handler
  var handlers = [];

//状况转移到胜利
  function fulfill(result) {
    state = FULFILLED;
    value = result;
  }
//状况转移到失利
  function reject(error) {
    state = REJECTED;
    value = error;
  }
}

到如今为止,我们给出了两个很地道的变化行动,在开辟的过程当中这两个行动会很不好用,所以我们在这两个行动的基础上构建一个高层次的行动(实在就是加点推断然后封装一层),就像下边这儿,名字就叫做resolve,然则注重和我们一般运用promise挪用的谁人resolve并不一样,不要搞混:

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

function Promise() {

  var state = PENDING;
  var value = null;
  var handlers = [];

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

  function reject(error) {
    state = REJECTED;
    value = error;
  }
//这里临时缺乏两个主要函数getThen和doResolve这两个函数,稍后会说道
  function resolve(result) {
    try {
      var then = getThen(result);
      //推断then是不是是一个Promise对象
      if (then) {
        doResolve(then.bind(result), resolve, reject)
        return
      }
      fulfill(result);
    } catch (e) {
      reject(e);
    }
  }
}

是的,我们的用到了两个辅佐函数getThen和doResolve,如今给出完成:

/**
 * 这里会推断value的范例,我们只需promise.then这个函数,其他的一切返回null
 *
 * @param {Promise|Any} value
 * @return {Function|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;
}

/**
 * 这个函数的主要作用就是串主逻辑,完成“变化状况”这个行动
 *
 * @param {Function} fn A resolver function that may not be trusted
 * @param {Function} onFulfilled
 * @param {Function} onRejected
 */
function doResolve(fn, onFulfilled, onRejected) {
//done的作用是让onFulfilled或许onRejected仅仅被挪用一次,状况机状况一旦转变没法转头
  var done = false;
  try {
//在我们一般运用Promise的时刻调的resolve,实在用的就是这里fn注入函数然后挪用
    fn(function (value) {
      if (done) return
      done = true
      **onFulfilled(value)**
    }, function (reason) {
      if (done) return
      done = true
      onRejected(reason)
    })
  } catch (ex) {
    if (done) return
    done = true
    onRejected(ex)
  }
}

构建

好了,一个完全的状况机已完成,我们完成了一个基础的状况变化逻辑,接下来要做的就是一步一步的朝promise规范进发,这个promise缺乏什么呢,临时缺的就是初始的行动啦(new promise(func)对象一旦被初始化内部代码马上实行),所以我们加上初始行动的开启

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

function Promise(fn) {

  var state = PENDING;
  var value = null;
  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实在就是你写的代码
  doResolve(fn, resolve, reject);
}

联动

我们完成了状况机,然则如今的题目是我们只能眼睁睁的看着代码的活动直到一个Promise完毕为止,即没法增加也没法猎取效果,这就有很大的局限性了,所以我们要运用then要领来串连Promise,用done要领来完成效果的网络,起首完成done要领,由于then实在说白了就是网络上边的效果–完成本身的逻辑–把效果传递给下一个Promise,做的事变是done的超集。

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

function Promise(fn) {

  var state = PENDING;
  var value = null;
  var handlers = [];

  function fulfill(result) {
    state = FULFILLED;
    value = result;
    //特地封装一个handle函数处置惩罚后续逻辑,鄙人面有this.handle(handler)要领
    handlers.forEach(handle);
    //在状况变成已处置惩罚而且之前到场的handler都被处置惩罚完毕的情况下再到场handler就会报错而且没有卵用
    handlers = null;
  }

  function reject(error) {
    state = REJECTED;
    value = error;
    handlers.forEach(handle);
    handlers = null;
  }

  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);
      }
    }
  }

//注重看下面done要领的完成,里边只要一个异步要领,换句话说就是会马上返回不会发生壅塞,我们以后会在then当中挪用done要领,这里的onFulfilled, onRejected就是用户写的处置惩罚函数,promise异步的特征就是如许来的。
  this.done = function (onFulfilled, onRejected) {
    // ensure we are always asynchronous
    setTimeout(function () {
      handle({
        onFulfilled: onFulfilled,
        onRejected: onRejected
      });
    }, 0);
  }

  doResolve(fn, resolve, reject);
}

末了,我们来完成Promise.then,完成状况机的串连:

//这段代码有点绕,主要须要完成的事情实在就是,推断上一个Promise是不是完成,然后实行用户的then里边的回调代码,并终究返回一个新的Promise,然后顺次轮回。。。
this.then = function (onFulfilled, onRejected) {
//开启then以后就会返回一个新的promise,然则这个时刻我们还可能有上一个Promise的使命没有完成,所以先把上边一个promise对象的this指向保留下来
  var self = this;
//返回一个新包装Promise,这和我们一般的在外边写new Promise是一个原理
  return new Promise(function (resolve, reject) {
//done的代码同样是马上返回,然后异步实行的
    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);
      }
    });
  });
}

Over
更多参考请看下面:
简朴的完成Promsie
高性能完成Promise,以及特地的wiki

    原文作者:2fa0
    原文地址: https://segmentfault.com/a/1190000013170460
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞