ES6之promise原理

栏目: JavaScript · 发布时间: 6年前

内容简介:Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数更强大,避免了层层回调。它由社区最早提出和实现,ES6将其写进了语言标准,统一了用法,现在原生提供Promise对象!Promise 是一个状态工具,他有三个状态:pending, fulfilled, reject,因此我们先定义三个状态。Promise 在执行完异步操作后,会转变状态,所以代码变为这样。

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数更强大,避免了层层回调。它由社区最早提出和实现,ES6将其写进了语言标准,统一了用法,现在原生提供Promise对象!

Promise使用:

// ... some code
const promise = new Promise(function(resolve, reject) {
  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});
复制代码
  • 我们可以看到,promise需要使用new操作符来生成实例,因此Promise是一个构造函数。
  • 这个promise初始化的时候需要传入一个函数做为参数,并且这个函数的两个参数分别为:resolve和reject。
  • resolve和reject是两个函数, 由 JavaScript 引擎提供 ,不用自己部署。
  • resolve函数的作用:将Promise对象状态从pending 变为 fulfilled
  • reject 函数的作用:将Promise对象状态从pending 变为 reject

现在让我们看一下promise的原理

Promise 是一个状态工具,他有三个状态:pending, fulfilled, reject,因此我们先定义三个状态。

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 or error once FULFILLED or REJECTED
  var value = null;

  // store sucess & failure handlers attached by calling .then or .done
  var handlers = [];
}
复制代码

Promise 在执行完异步操作后,会转变状态,所以代码变为这样。

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;
  }
}
复制代码

上面fulfill是一个比较low level的转变状态方法,但是有一个higher-level的转变状态方法: 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 {
      var then = getThen(result);
      if (then) {
        doResolve(then.bind(result), resolve, reject)
        return
      }
      fulfill(result);
    } catch (e) {
      reject(e);
    }
  }
}
复制代码

可以看到resolve先调用了方法getThen(),这个方法是判断result是否是promise,如果是的话,调用这个promise的then方法(使用doResolve()方法),如果不是的话,调用fulfill()方法。

/**
 * Check if a value is a Promise and, if it is,
 * return the `then` method of that promise.
 *
 * @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;
}

/**
 * Take a potentially misbehaving resolver function and make sure
 * onFulfilled and onRejected are only called once.
 *
 * Makes no guarantees about asynchrony.
 *
 * @param {Function} fn A resolver function that may not be trusted
 * @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)
    })
  } catch (ex) {
    if (done) return
    done = true
    onRejected(ex)
  }
}
复制代码

这里可以看到,什么情况会reject:catch到的错误会reject, 到现在为止,我们完成了内部状态机,可是介绍resolving这个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);
}
复制代码

只添加了最后一句代码: 我们re-use了doResolve()方法!

现在我们已经完成了状态机,可是我们仍然无法监听变化,我们的最终目标是实现.then(), 但是.done()这个更简单,因此,让我们先实现.done()吧! 所以我们的目标是实现promise.done(onFulfilled, onRejected), 他有以下特点

  • 只调用 onFulfilled or onRejected 中的一个
  • 只调用一次
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;
    handlers.forEach(handle);
    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);
      }
    }
  }

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

  doResolve(fn, resolve, reject);
}
复制代码

this.done方法做的事情:执行了handle方法,并传入参数,其中参数就是第一个是成功时候回调函数,第二个是reject时候的回调函数。

现在让我们实现.then吧~

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);
      }
    });
  });
}
复制代码
  • .then 和.done一样,接受两个参数,第一个是成功时候回调函数onFulfilled,第二个是失败时候回调函数onRejected。
  • .then 能实现链式调用,就是因为其返回了一个promise。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

部落:一呼百应的力量

部落:一呼百应的力量

高汀 (Godin.S.) / 刘晖 / 中信出版社 / 2009-7 / 26.00元

部落指的是任何一群人,规模可大可小,他们因追随领导、志同道合而相互联系在一起。人类其实数百万年前就有部落的出现,随之还形成了宗教、种族、政治或甚至音乐。 互联网消除了地理隔离,降低了沟通成本并缩短了时间。博客和社交网站都有益于现有的部落扩张,并促进了网络部落的诞生——这些部落的人数从10个到1000万个不等,他们所关注的也许是iPhone,或一场政治运动,或阻止全球变暖的新方法。 那么......一起来看看 《部落:一呼百应的力量》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

MD5 加密
MD5 加密

MD5 加密工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具