美文网首页ES6
ES6 官方Promise实现原理及源码解析

ES6 官方Promise实现原理及源码解析

作者: 赵一鸣的笔记本 | 来源:发表于2018-04-06 22:02 被阅读90次

根据官方Promise用法,结合个人思路,试着实现Promise,通过每次git提交,记录自己的思路,持续修改更新中!

注意:熟悉Promise基本用法之后再阅读此文会更好,可参考中文版《Promises/A+规范》:
http://www.ituring.com.cn/article/66566

1、简易实例

var p = new Promise(function (resolve, reject) {
  $.ajax({
    type: 'POST',
    url: 'http://www.zymseo.com/qianduan',
    data: {
      uname: 'zhaoyiming',
      upwd: '123456'
    },
    dataType: 'json',
    success: function (res) {
      res.errorCode === 200 ? resolve(res) : reject(res);
    },
    error: function (res) {
      reject(res);
    }
  });
});

p.then(function (value) {
  console.log(value);
}, function (reason) {
  console.log(reason);
});

从以上代码可以看出,Promise是一个构造函数,实例化之后,可以通过它的then方法【注册】promise异步操作成功时执行的回调,使得异步调用变得非常简单方便。

之所以说是注册,是因为它就是一种【发布订阅模式】,详细参考《JavaScript发布与订阅模式详解》: http://www.zymseo.com/508.html

2、试着实现一个Promise雏形

function Promise (fn) {
  this.handles = {
    resolves: [],
    rejects: []
  };
}

Promise.prototype.then = function (resolve, reject) {
  return this;
};

通过then方法,将执行成功或失败之后的回调函数放入队列里边(Promise内部定义的handles对象,resolves存放成功时的回调,rejects存放失败时的回调)。

既然是发布订阅模式,那么首先得订阅,就像我们看到某些杂志的文章非常好,就可以订阅他们的邮箱,这样每天有新的文章更新时,我们的邮箱才能收到并提醒我们去阅读。

所以,resolve和reject的执行必须是包含在一个异步方法内(ajax,setTimeout等等),这个时候,会首先执行then,最后异步执行完成之后再依次执行通过then注册的回调。

then中return this,实现了链式调用。

3、Promise内部加入延时机制

理论上,Promise内都是做异步操作的,但是没法保证所有的人都这样做(心急写代码忘了呢-).

也就是在then方法注册回调之前,resolve或reject函数就执行了。

这显然是不允许的,Promises/A+规范明确要求回调需要通过异步方式执行,用以保证一致可靠的执行顺序。

var p = new Promise(function (resolve, reject) {
  // do something...
  resolve(value);
});

p.then(function (res) {
  console.log(res);
});

我们可以做一些处理,保证在resolve执行之前,then方法已经注册完所有的回调:在Promise内部,将resolve或reject包裹在setTimeout内:

function Promise (fn) {
  this.handles = {
    resolves: [],
    rejects: []
  };

  var _this = this;

  fn(function (value) {
    setTimeout(function () {
      for (var i = 0, len = _this.handles.resolves.length; i < len; i += 1) {
        _this.handles.resolves[i]();
      }
    }, 0);
  }, function (reason) {
    setTimeout(function () {
      for (var i = 0, len = _this.handles.rejects.length; i < len; i += 1) {
        _this.handles.rejects[i]();
      }
    }, 0);
  });
}

但是,这样好像还存在一个问题,可以细想一下:如果Promise异步操作已经成功,这时,在异步操作成功之前注册的回调都会执行,但是在Promise异步操作成功这之后调用的then注册的回调就再也不会执行了,这肯定是不行的。

4、通过状态来决定回调什么时候执行

Promises/A+规范中的2.1 Promise States中明确规定了,pending可以转化为fulfilled或rejected并且只能转化一次,也就是说如果pending转化到fulfilled状态,那么就不能再转化到rejected。并且fulfilled和rejected状态只能由pending转化而来,两者之间不能互相转换。如图所示:

image
function Promise (fn) {
  this.handles = {
    resolves: [],
    rejects: []
  };
  this.status = 0; // 0: pending 1: resolve 2: reject
}

Promise.prototype.then = function (resolve, reject) {
  switch (this.status) {
    case 0: // 如果是pedding状态,则将回调加入到队列
      addQueue(this, resolve, reject);
      break;
    case 1: // 如果异步已经执行成功,则立刻执行then中注册的resolve方法
      resolve(this.value);
      break;
    default: // 如果异步已经执行失败,则立刻执行then中注册的reject方法
      reject(this.value);
  }
  return this;
};

function addQueue (self, resolve, reject) {
  typeof resolve === 'function' && self.handles.resolves.push(resolve);
  typeof reject === 'function' && self.handles.rejects.push(reject);
}

5、总结

通过Promise.prototype.then方法将观察者方法注册到被观察者Promise对象中,同时返回一个新的Promise对象,以便可以链式调用。

被观察者管理内部pending、fulfilled和rejected的状态转变,同时通过构造函数中传递的resolve和reject方法以主动触发状态转变和通知观察者。

了解了Promise执行原理,再去扩展then之后的其他方法就很好做了。例如Promise.all() Promise.rece()等等。

本文关于Promise源码都放到了Github上 https://github.com/zymseo/Promise/blob/master/src/promise.js ,实现了Promise大多数方法,可以作为参考。

查看原文: http://www.zymseo.com/509.html

个人微信&QQ:1047832475

相关文章

  • ES6 官方Promise实现原理及源码解析

    根据官方Promise用法,结合个人思路,试着实现Promise,通过每次git提交,记录自己的思路,持续修改更新...

  • js Promise实现笔记

    V8引擎的实现源码:promise.js非官方实现,来自:Promise实现原理(附源码)注:啃官方源码和其他原型...

  • Promise对象原理解析

    Promise对象原理解析 ES6 原生提供了 Promise 对象。所谓 Promise,就是一个对象,用来传递...

  • redux-promise解析

    redux-promise 解析这个中间的用法,以及原理 源码 用法 虽然官方文档上面并没有举例是如何使用(至这篇...

  • CopyOnWriteArrayList

    实现原理 源码解析 面试

  • 手写Promise

    参考:Promise实现原理(附源码) promise的注意点: Promise特点 1.状态不可变 2.值穿透,...

  • Promise原理解析

    Promise原理解析 标签(空格分隔): Node.js Promise原理解析 简介 Promise 对象用于...

  • ConcurrentHashMap 原理解析(JDK1.8)

    了解ConcurrentHashMap 实现原理,建议首先了解下HashMap实现原理。HashMap 源码解析(...

  • Promise原理分析及源码实现

    为什么用Promise? Promise能解决回调地狱问题 Promise能多个异步操作并行,获取最终结果 Pro...

  • 实现 Promise

    实现 Promise 此代码基本源于大佬在掘金上发的文章Promise实现原理(附源码), 此文写得相当详细, 非...

网友评论

    本文标题:ES6 官方Promise实现原理及源码解析

    本文链接:https://www.haomeiwen.com/subject/lgtehftx.html