资讯专栏INFORMATION COLUMN

promise源码库

魏明 / 2823人阅读

摘要:先直接上源码吧。阮一峰在基础篇提到过,阮一峰基础介绍,返回的是一个新的实例,不是原来的那个实例。同理绑定和的指向。秒后,是为了让在队列的最后执行。此时将中第一个回调函数执行的赋值给了。这就验证了阮一峰在基础介绍将的下面的代码逻辑。

先直接上源码吧。

</>复制代码

  1. if(!window.Promise) {
  2. function Promise(fn) {
  3. var self=this;
  4. this.status = "pending";
  5. this.thenCache = [];
  6. this.count = 0
  7. if(!(this instanceof Promise)) {
  8. throw "Defer is a constructor and should be called width "new" keyword";
  9. }
  10. if(typeof fn !== "function") {
  11. throw "Defer params must be a function";
  12. }
  13. //为了让传进来的函数在then后执行
  14. setTimeout(function() {
  15. try {
  16. fn.call(this, self.resolve.bind(self), self.reject.bind(self))
  17. } catch(e) {
  18. self.reject(e);
  19. }
  20. }, 0);
  21. }
  22. Promise.prototype.resolve = function(value) {
  23. this.value = value;
  24. this.status = "resolved";
  25. this.triggerThen();
  26. }
  27. Promise.prototype.reject = function(reason) {
  28. this.value = reason;
  29. this.status = "rejected";
  30. this.triggerThen();
  31. }
  32. Promise.prototype.then = function(onResolve, onReject) {
  33. this.thenCache.push({ onResolve: onResolve, onReject: onReject });
  34. console.log("this", this)
  35. return this;
  36. }
  37. Promise.prototype.catch = function(fn) {
  38. if(typeof fn === "function") {
  39. this.errorHandle = fn;
  40. }
  41. };
  42. Promise.prototype.triggerThen = function() {
  43. console.log("this.thenCache", this.thenCache)
  44. console.log("this.status", this.status)
  45. var current = this.thenCache.shift(),
  46. res;
  47. console.log("current", current)
  48. if(!current && this.status === "resolved") {
  49. // console.log("--11--", + new Date())
  50. return this;
  51. } else if(!current && this.status === "rejected") {
  52. if(this.errorHandle) {
  53. this.value = this.errorHandle.call(undefined, this.value);
  54. this.status = "resolved";
  55. console.log("--11--", + new Date())
  56. }
  57. return this;
  58. };
  59. if(this.status === "resolved") {
  60. // console.log("--222--", + new Date())
  61. res = current.onResolve;
  62. } else if(this.status === "rejected") {
  63. console.log("--222--", + new Date())
  64. res = current.onReject;
  65. }
  66. this.count ++;
  67. if(typeof res === "function") {
  68. try {
  69. this.value = res.call(undefined, this.value);
  70. this.status = "resolved";
  71. console.log("-ffffd--", + new Date())
  72. this.triggerThen();
  73. // console.log("this.count", this.count, + new Date())
  74. } catch(e) {
  75. this.status = "rejected";
  76. this.value = e;
  77. return this.triggerThen();
  78. }
  79. } else {
  80. console.log("--44--")
  81. this.triggerThen();
  82. }
  83. }
  84. window.Promise = Promise;
  85. }

之前写过如何构造一个promise库,参考的美团点评的网站,写到后面发现Promise.resolve()直接调用就会出现问题。报错上面的库,也是引用Talking Coder的一篇博客,逐渐开始理解promise内部是如何实现的了,当然还是有一些疑问。比如上面的库,需要注释window.Promise = Promise和if(!window.Promise) {} 内部的代码在debug的时候才能看得见。但如果注释掉,直接Promise.resolve()又回同样报resolve不是一个方法。

阮一峰在promise基础篇提到过,阮一峰promise基础介绍,then返回的是一个新的Promise实例,不是原来的那个实例。这里提到的原来的那个实例,我想应该是第一次实例化的Promise实例对象。这里有点不懂,为何then函数在return this后,就会返回一个新的Promise实例对象。

大概讲解下此Promise库的原理吧。

</>复制代码

  1. setTimeout(function() {
  2. try {
  3. fn.call(this, self.resolve.bind(self), self.reject.bind(self))
  4. } catch(e) {
  5. self.reject(e);
  6. }
  7. }, 0);

call 和 bind 都是为了绑定this的指向,因为直接回调,this在浏览器里面指向的是window对象,绑定fn执行的时候this指向Promise的实例对象。同理绑定resolve和reject的this指向。
setTimout 0秒后,是为了让fn在队列的最后执行。这里的队列一会再剖析。或者说让resolve或reject在队列的最后执行。
如果去掉setTimeout 0秒后,那么在实例化Promise的时候,就会立刻执行回调fn,进而执行resolve或reject函数,而此时then还未来得及push需要thenAble的回调队列,导致再执行resolve或reject里面的triggerThen()方法时,无法执行(此时回调队列为空。)

</>复制代码

  1. Promise.prototype.then = function(onResolve, onReject) {
  2. this.thenCache.push({ onResolve: onResolve, onReject: onReject });
  3. return this;
  4. }

then 实际是一个回调队列,当有3个then,那么回调队列就会有三个。然后通this.triggerThen()
以此递归调用,直接回调队列被调用完毕后,再执行fn中的resolve或reject函数。

再分析下状态和返回值
在triggerThen函数里有这么几行代码

</>复制代码

  1. if(typeof res === "function") {
  2. try {
  3. this.value = res.call(undefined, this.value);
  4. this.status = "resolved";
  5. this.triggerThen();
  6. } catch(e) {
  7. this.status = "rejected";
  8. this.value = e;
  9. return this.triggerThen();
  10. }
  11. } else {
  12. this.triggerThen();
  13. }

可以看出,当js无语法报错的时候,执行的try代码。此时将then()中第一个回调函数执行的value赋值给了this.value。在new Promise()的回调函数中,如果执行过resolve()的话,那么此时赋值就是第二次赋值了。同理this.status。当出现语法报错的时候,会执行catch,此时将错误参数e同样赋值给this.value。状态也被变为rejected。同理如果在new Promise()回调中执行过reject,那么此时赋值也是第二次赋值了。这就验证了阮一峰在Promise基础介绍将的下面的代码逻辑。

</>复制代码

  1. const promise = new Promise(function(resolve, reject) {
  2. throw new Error("test");
  3. });
  4. promise.catch(function(error) {
  5. console.log(error);
  6. });
  7. // Error: test

catch 跟then的第二个参数是一个逻辑。而且then的第二个参数实际我们很少回调。都写catch来异常捕获的。

其实写这篇文章的时候,对Promise还是了解在表面上,但收获依然还是有的,准建理解了Promise是如何实现的,比如resolve和then回调的关系,

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/93105.html

相关文章

  • 源码Promise 概念与实现

    摘要:从源码看概念与实现是异步编程中的重要概念,它较好地解决了异步任务中回调嵌套的问题。这些概念中有趣的地方在于,标识状态的变量如都是形容词,用于传入数据的接口如与都是动词,而用于传入回调函数的接口如及则在语义上用于修饰动词的副词。 从源码看 Promise 概念与实现 Promise 是 JS 异步编程中的重要概念,它较好地解决了异步任务中回调嵌套的问题。在没有引入新的语言机制的前提下,这...

    kel 评论0 收藏0
  • 小而美的Promise——promiz源码浅析

    摘要:因此,当作为参数的执行任意结果的回调函数时,就会将参数传递给外层的,执行对应的回调函数。 背景 在上一篇博客[[译]前端基础知识储备——Promise/A+规范](https://segmentfault.com/a/11...,我们介绍了Promise/A+规范的具体条目。在本文中,我们来选择了promiz,让大家来看下一个具体的Promise库的内部代码是如何运作的。 promiz...

    figofuture 评论0 收藏0
  • 深入koa源码(二):核心原理

    摘要:最近读了的源码,理清楚了架构设计与用到的第三方库。本系列将分为篇,分别介绍的架构设计和个核心库,最终会手动实现一个简易的。本文来自心谭博客深入源码核心库原理所有系列文章都放在了。这一段逻辑封装在了核心库里面。 最近读了 koa2 的源码,理清楚了架构设计与用到的第三方库。本系列将分为 3 篇,分别介绍 koa 的架构设计和 3 个核心库,最终会手动实现一个简易的 koa。这是系列第 2...

    tyheist 评论0 收藏0
  • thunkify与co源码解读

    开头 首先本文有将近3000字,阅读可能会占用你20分钟左右。 文笔可能不佳,希望能帮助到阅读此文的人有一些收获 在进行源码阅读前首先抱有一个疑问,thunk函数是什么,thunkify库又是干什么的,co又是干嘛,它有啥用 程序语言有两种求值策略 传名调用 传入参数实际上是传入函数体 传值调用 函数体在进入的时候就进行运算计算值 编译器的传名调用实现,往往是将参数放到一个临时函数之中,再将这个...

    Tangpj 评论0 收藏0
  • co 函数

    摘要:参考函数库是用于函数自动执行的一个小工具。是一个函数函数返回一个函数执行完成上面代码中,等到函数执行结束,就会输出一行提示。函数其实就是将两种自动执行器函数和对象,包装成一个库。使用的前提是,函数内的命令后面,只能是函数或者对象。 参考 reference 1 reference 2 co 函数库是用于 Generator 函数自动执行的一个小工具。 usge var co = r...

    张红新 评论0 收藏0

发表评论

0条评论

魏明

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<