资讯专栏INFORMATION COLUMN

Promise-resolve流程源码剖析

Amos / 1867人阅读

原文链接:链接

1 最简单一个案例

</>复制代码

  1. function runAsync(){
  2. let p = new Promise(function(resolve,reject){
  3. console.log("exec");
  4. setTimeout(function(){
  5. resolve("someData");
  6. },2000);
  7. });
  8. return p;
  9. }
  10. var promise = runAsync();
  11. promise.then(function(data){
  12. console.log(data);
  13. });
  14. console.log("同步执行");
  15. console.log(promise);

控制台输出

</>复制代码

  1. exec
  2. 同步执行
  3. Promise
  4. //两秒后
  5. someData
2 Promise内部是如何运行的? 2.1 执行这行代码的时候:let p = new Promise(f);

</>复制代码

  1. function noop() {}
  2. function Promise(fn) {
  3. if (typeof this !== "object") {
  4. throw new TypeError("Promises must be constructed via new");
  5. }
  6. if (typeof fn !== "function") {
  7. throw new TypeError("Promise constructor"s argument is not a function");
  8. }
  9. this._deferredState = 0;
  10. this._state = 0;
  11. this._value = null;
  12. this._deferreds = null;
  13. //注意这里,如果fn传入的是noop这个函数,那么不会执行doResolve
  14. if (fn === noop) return;
  15. doResolve(fn, this);
  16. }
  17. Promise._onHandle = null;
  18. Promise._onReject = null;
  19. Promise._noop = noop;
  20. function doResolve(fn, promise) {
  21. var done = false;
  22. var res = tryCallTwo(fn, function (value) {
  23. if (done) return;
  24. done = true;
  25. resolve(promise, value);
  26. }, function (reason) {
  27. if (done) return;
  28. done = true;
  29. reject(promise, reason);
  30. });
  31. if (!done && res === IS_ERROR) {
  32. done = true;
  33. reject(promise, LAST_ERROR);
  34. }
  35. }
  36. function tryCallTwo(fn, a, b) {
  37. try {
  38. fn(a, b);
  39. } catch (ex) {
  40. LAST_ERROR = ex;
  41. return IS_ERROR;
  42. }
  43. }

可以看到 let p = new Promise( f );在 传入的 f. 函数不是noop的时候,

第一会先执行 f 函数

第二生成一个Promise对象

</>复制代码

  1. p =>{
  2. _deferredState:0,//deffer的状态,代表的应该是 _deferreds 的类型,1 是 single,2 是 Array
  3. _state:0,//每个promise对象的状态维护标识
  4. _value:null,//resolve函数执行的时候,异步得到的结果
  5. _deferreds:null
  6. }
2.2执行这行代码的时候: promise.then(function(data){ console.log(data);});

</>复制代码

  1. Promise.prototype.then = function(onFulfilled, onRejected) {
  2. if (this.constructor !== Promise) {//这些比较的都是引用地址;
  3. return safeThen(this, onFulfilled, onRejected);
  4. }
  5. var res = new Promise(noop);
  6. handle(this, new Handler(onFulfilled, onRejected, res));
  7. //注意这里 then的链式调用,每次then函数执行完毕之后,返回值都是一个新的Promise实例对象,
  8. return res;
  9. };
  10. //这里生成一个deffer对象,保存then函数中注册的onFulfilled和onRejected回调,以及要返回的新的promise实例对象
  11. function Handler(onFulfilled, onRejected, promise){
  12. this.onFulfilled = typeof onFulfilled === "function" ? onFulfilled : null;
  13. this.onRejected = typeof onRejected === "function" ? onRejected : null;
  14. this.promise = promise;
  15. }
  16. function handle(self, deferred) {
  17. //不会进入这里
  18. while (self._state === 3) {
  19. self = self._value;
  20. }
  21. //也不会进入这里
  22. if (Promise._onHandle) {
  23. Promise._onHandle(self);
  24. }
  25. //进入这里,注意这里,如果通过then的链式调用,那么每次then返回的对象都是一个新的类似于下面 p 实例对象;
  26. if (self._state === 0) {
  27. if (self._deferredState === 0) {
  28. self._deferredState = 1;
  29. self._deferreds = deferred;
  30. return;
  31. //第一次执行到这里即结束;
  32. }
  33. if (self._deferredState === 1) {
  34. self._deferredState = 2;
  35. self._deferreds = [self._deferreds, deferred];
  36. return;
  37. }
  38. self._deferreds.push(deferred);
  39. return;
  40. }
  41. //这个函数只有当 _state的值为 1 2的时候才会执行
  42. handleResolved(self, deferred);
  43. }

此时再来看下p这个promise实例的属性值

</>复制代码

  1. p =>{
  2. _deferredState:1,//deffer的状态
  3. _state:0,//每个promise对象的状态维护标识
  4. _value:null,//resolve函数执行的时候,异步得到的结果
  5. _deferreds: new Handler(onFulfilled, onRejected, res)//存放通过then注册的函数以及返回的❤️Promise实例对象的一个Handler对象;
  6. }
  7. res:{
  8. _deferredState:0,//deffereds的状态,
  9. _state:0,//每个promise对象的状态维护标识
  10. _value:null,//resolve函数执行的时候,异步得到的结果
  11. _deferreds:null
  12. }

如果返回的res在执行then方法,那么

</>复制代码

  1. p =>{
  2. _deferredState:1,//deffer的状态
  3. _state:0,//每个promise对象的状态维护标识
  4. _value:null,//resolve函数执行的时候,异步得到的结果
  5. _deferreds: new Handler(onFulfilled, onRejected, res)//存放通过then注册的函数以及返回的❤️Promise实例对象的一个Handler对象;
  6. }
  7. res:{
  8. _deferredState:1,//deffereds的状态,
  9. _state:0,//每个promise对象的状态维护标识
  10. _value:null,//resolve函数执行的时候,异步得到的结果
  11. _deferreds:new Handler(onFulfilled, onRejected, res)//存放通过then注册的函数以及返回的❤️Promise实例对象的一个Handler对象;
  12. }
2.3 异步操作完成以后:resolve("someData");

</>复制代码

  1. //真正调用这个函数的是tryCallTwo中的第二个函数入参;self就是p这个promise实例对象;
  2. function resolve(self, newValue) {
  3. // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
  4. //对于此时的案例,不会进入这里
  5. if (newValue === self) {
  6. return reject(
  7. self,
  8. new TypeError("A promise cannot be resolved with itself.")
  9. );
  10. }
  11. //也不会进入这里
  12. if (
  13. //比如resolve(p1) p1是一个新的promise对象;
  14. newValue &&
  15. (typeof newValue === "object" || typeof newValue === "function")
  16. ) {
  17. var then = getThen(newValue);
  18. if (then === IS_ERROR) {
  19. return reject(self, LAST_ERROR);
  20. }
  21. if (
  22. then === self.then &&
  23. newValue instanceof Promise
  24. ) {
  25. self._state = 3;
  26. self._value = newValue;
  27. finale(self);
  28. return;
  29. } else if (typeof then === "function") {
  30. doResolve(then.bind(newValue), self);
  31. return;
  32. }
  33. }
  34. //对于简单的返回值,比如后台返回的JSON字符串等,这里就直接进行处理;
  35. self._state = 1;//fulfilled
  36. self._value = newValue;//给这个promise对象添加属性值 _value,用来保存异步操作的结果;
  37. finale(self);//最后处理这个promise对象
  38. }

此时的promise实例对象,关注对比p这个实例对象的变化,可以看到resolve之后,相当于将异步的结果给到了p这个Promise实例对象的_value属性值,同时改变这个p的状态_state为1 ==> fulfilled

</>复制代码

  1. p =>{
  2. _deferredState:1,//deffer的状态
  3. _state:1,//每个promise对象的状态维护标识
  4. _value:"someData",//resolve函数执行的时候,异步得到的结果
  5. _deferreds: new Handler(onFulfilled, onRejected, res)
  6. }
2.4 finale(self);//最后处理这个promise对象

</>复制代码

  1. function finale(self) {
  2. //进入这个if语句
  3. if (self._deferredState === 1) {
  4. handle(self, self._deferreds);
  5. self._deferreds = null;
  6. }
  7. if (self._deferredState === 2) {
  8. for (var i = 0; i < self._deferreds.length; i++) {
  9. handle(self, self._deferreds[i]);
  10. }
  11. self._deferreds = null;
  12. }
  13. }

</>复制代码

  1. function handle(self, deferred) {
  2. while (self._state === 3) {
  3. self = self._value;
  4. }
  5. if (Promise._onHandle) {
  6. Promise._onHandle(self);
  7. }
  8. //此时不会进入这里因为 _state的值为 1
  9. if (self._state === 0) {
  10. if (self._deferredState === 0) {
  11. self._deferredState = 1;
  12. self._deferreds = deferred;
  13. return;
  14. }
  15. if (self._deferredState === 1) {
  16. self._deferredState = 2;
  17. self._deferreds = [self._deferreds, deferred];
  18. return;
  19. }
  20. self._deferreds.push(deferred);
  21. return;
  22. }
  23. //这个函数只有当 _state的值为 1 fulfilled. 2 rejected 的时候才会执行
  24. handleResolved(self, deferred);
  25. }

</>复制代码

  1. function handleResolved(self, deferred) {
  2. asap(function() {
  3. //得到promise.then(function(data){ console.log(data);});注册的函数
  4. var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
  5. if (cb === null) {
  6. if (self._state === 1) {
  7. resolve(deferred.promise, self._value);
  8. } else {
  9. reject(deferred.promise, self._value);
  10. }
  11. return;
  12. }
  13. //执行then中注册回调函数
  14. var ret = tryCallOne(cb, self._value);
  15. if (ret === IS_ERROR) {
  16. reject(deferred.promise, LAST_ERROR);
  17. } else {
  18. resolve(deferred.promise, ret);
  19. }
  20. });
  21. };
  22. function tryCallOne(fn, a) {
  23. try {
  24. return fn(a);
  25. } catch (ex) {
  26. LAST_ERROR = ex;
  27. return IS_ERROR;
  28. }
  29. }

至此一个简单的promsie的实现流程完毕;

下面用实际的例子来看下:

3 对于then的链式调用,Promise内部又是如何运行的呢? 下一个then中注册的函数会接收到上一个then的返回值作为该then中注册的函数的参数; 3.1 then注册的函数返回基本数据类型

</>复制代码

  1. function runAsync(){
  2. let p = new Promise(function(resolve,reject){
  3. console.log("exec");
  4. setTimeout(function(){
  5. resolve("someData");
  6. },2000);
  7. });
  8. return p;
  9. }
  10. var promise = runAsync();
  11. promise.then(function(data){
  12. console.log(data);
  13. return "someData1"
  14. }).then(function(data){
  15. console.log(data);
  16. return "someData2"
  17. }).then(function(data){
  18. console.log(data)
  19. })
  20. console.log("同步执行");
  21. console.log(promise);

控制台输出

</>复制代码

  1. exec
  2. 同步执行
  3. Promise
  4. //两秒后
  5. someData
  6. someData1
  7. someData2

resolve(deferred.promise, ret);中的ret值就是then中注册函数的返回值,这里就是一些简单的字符串"someData1" "someData2"

</>复制代码

  1. promise实例对象==> 异步成功 ==> 该实例对象的resolve(data) ==>
  2. //newValue为异步得到的数据,第一次是"someData"这个字符串,下一次就是then中注册函数的返回值ret,还是字符串"someData1" "someData2"
  3. resolve(self,newValue) ==> <== == == == == == == ||
  4. ^
  5. ==>handle(self,deffer) ||
  6. ^
  7. ==>handleResolved处理then中注册的函数; ||
  8. ^
  9. ==>接着处理下一个promis==>resolve(deferred.promise, ret); ===> ||

</>复制代码

  1. var p = {
  2. _deferredState:1,//deffer的状态
  3. _state:0,//每个promise对象的状态维护标识
  4. _value:null,//resolve函数执行的时候,异步得到的结果
  5. _deferreds:{
  6. onFulfilled:onFulfilled,
  7. onRejected:onRejected,
  8. promise:{//这里是 new Promise(noop)
  9. _deferredState:1,
  10. _state:0,
  11. _value:null,
  12. _deferreds:{//通过then注册的执行对象
  13. onFulfilled:onFulfilled,
  14. onRejected:onRejected,
  15. promise:{//这里是 new Promise(noop)
  16. _deferredState:1,
  17. _state:0,
  18. _value:null,
  19. _deferreds:{//通过then注册的执行对象
  20. onFulfilled:onFulfilled,
  21. onRejected:onRejected,
  22. promise:{//这里是 new Promise(noop)
  23. _deferredState:1
  24. _state:0,
  25. _value:null,
  26. _deferreds:null
  27. },
  28. }
  29. }
  30. }
  31. }
  32. }
  33. };
3.2 then注册的函数返回一个新的promise

</>复制代码

  1. function runAsync(){
  2. let p = new Promise(function(resolve,reject){
  3. console.log("exec");
  4. setTimeout(function(){
  5. resolve("someData");
  6. },2000);
  7. });
  8. return p;
  9. };
  10. function runAsync1(){
  11. return new Promise(function(resolve,reject){
  12. setTimeout(function(){
  13. resolve("someData1");
  14. },2000);
  15. })
  16. };
  17. function runAsync2(){
  18. return new Promise(function(resolve,reject){
  19. setTimeout(function(){
  20. resolve("someData2");
  21. },2000);
  22. })
  23. };
  24. //以下的异步操作会按照顺序进行执行;
  25. var promise = runAsync();
  26. promise.then(function(data){
  27. console.log(data);
  28. return runAsync1()
  29. }).then(function(data){
  30. console.log(data);
  31. return runAsync2()
  32. }).then(function(data){
  33. console.log(data);
  34. // return "someData3"
  35. })
  36. console.log("同步执行");
  37. console.log(promise);

控制台输出

</>复制代码

  1. exec
  2. 同步执行
  3. Promise
  4. //两秒后
  5. someData
  6. //两秒后
  7. someData1
  8. //两秒后
  9. someData2

</>复制代码

  1. promise实例对象 ==> 异步成功 ==> 该实例对象的resolve(data) ==>
  2. //newValue为异步得到的数据,这里第一次是 "someData"这个字符串,下一次就是then中注册函数的返回值,这里就是runAsync返回的promise对象
  3. resolve(self,newValue) ==> <== == == == == == == ||
  4. ^
  5. ==>handle(self,deffer) ||
  6. ^
  7. ==>handleResolved处理then中注册的函数; ||
  8. ^
  9. ==>接着处理下一个promise==>resolve(deferred.promise, ret); ===> ||

整个promise链如下

</>复制代码

  1. var p = {
  2. _deferredState:1,//deffer的状态
  3. _state:0,//每个promise对象的状态维护标识
  4. _value:null,//resolve函数执行的时候,异步得到的结果
  5. _deferreds:{
  6. onFulfilled:onFulfilled,
  7. onRejected:onRejected,
  8. promise:{ //通过引用的地址改变,这里是runAsync返回的promise
  9. _deferredState:1,
  10. _state:0,
  11. _value:null,
  12. _deferreds:{//由于runAsync中没有执行then注册,这里将new Promise(noop) 通过then注册的对象引用拿到;
  13. onFulfilled:onFulfilled,
  14. onRejected:onRejected,
  15. promise:{//通过引用的地址改变,这里是runAsync返回的promise
  16. _deferredState:1,
  17. _state:0,
  18. _value:null,
  19. _deferreds:{
  20. onFulfilled:onFulfilled,
  21. onRejected:onRejected,
  22. promise:{//通过引用的地址改变,这里是runAsync返回的promise
  23. _deferredState:1,
  24. _state:0,
  25. _value:null,
  26. _deferreds:null
  27. },
  28. }
  29. }
  30. }
  31. }
  32. }
  33. }
3.3 以上两者有何差异?

相同点:每个then返回的新的promise对象是一样的,都是通过then函数中的定义的返回值:var res = new Promise(noop);

不同点:在handleResolved中,resolve(deferred.promise, ret);中的ret的值不同,ret就是每个then中注册的函数的返回值,对比以上两种情况,一个返回基本数据类型,一个返回Promise对象,接下来重点看下then中注册的函数返回promise对象的情况(注意这个和then链式调用的promise对象不是一个)

</>复制代码

  1. // resolve(deferred.promise, ret);注意这个self,传入的是deferred这个对象中promise这个引用地址;
  2. //真正调用这个函数的是tryCallTwo中的第二个函数入参;self就是p这个promise实例对象;
  3. function resolve(self, newValue) {
  4. //此时的newValue是then中注册函数的返回的Promise实例对象
  5. //self是deferred.promise
  6. // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
  7. //对于此时的案例,不会进入这里
  8. if (newValue === self) {
  9. return reject(
  10. self,
  11. new TypeError("A promise cannot be resolved with itself.")
  12. );
  13. }
  14. //注意,对于then中注册的函数返回值是一个新的promise对象的时候,此时会进入这里
  15. if (
  16. //比如resolve(p1) p1是一个新的promise对象;
  17. newValue &&
  18. (typeof newValue === "object" || typeof newValue === "function")
  19. ) {
  20. var then = getThen(newValue);
  21. if (then === IS_ERROR) {
  22. return reject(self, LAST_ERROR);
  23. }
  24. if (
  25. //两个Promise对象原型链上都是引用的then这个函数地址
  26. then === self.then &&
  27. newValue instanceof Promise
  28. ) {
  29. self._state = 3;
  30. self._value = newValue;
  31. finale(self);
  32. //执行到这里,结束;
  33. return;
  34. } else if (typeof then === "function") {
  35. doResolve(then.bind(newValue), self);
  36. return;
  37. }
  38. }
  39. //对于then中注册的函数返回一个promise对象的情况,下面就不会执行
  40. self._state = 1;
  41. self._value = newValue;
  42. finale(self);
  43. }

self ==> deferred.promise

</>复制代码

  1. function finale(self) {
  2. if (self._deferredState === 1) {
  3. handle(self, self._deferreds);
  4. self._deferreds = null;
  5. }
  6. if (self._deferredState === 2) {
  7. for (var i = 0; i < self._deferreds.length; i++) {
  8. handle(self, self._deferreds[i]);
  9. }
  10. self._deferreds = null;
  11. }
  12. }

注意在这里通过对promise链进行引用的改变,从而使异步的执行看起来和同步是一样的;

handle函数有两个作用,

第一:改变promise链的引用,将原本返回的 new Promsie(noop) 改为ret(then中注册函数返回的promise)

第二:将原本new Promsie(noop) 上面通过then注册deferred对象,给到ret响应的属性

</>复制代码

  1. function handle(self, deferred) {
  2. while (self._state === 3) {
  3. //这里一直循环直到取到我们返回的promsie对象,也就是上面的ret,即每个runAsync函数的返回值;
  4. self = self._value;
  5. }
  6. if (Promise._onHandle) {
  7. Promise._onHandle(self);
  8. }
  9. //将runAsync的返回的promise对象中_deferredState设置为 1;
  10. if (self._state === 0) {
  11. if (self._deferredState === 0) {
  12. self._deferredState = 1;
  13. self._deferreds = deferred;
  14. //执行到这里结束
  15. return;
  16. }
  17. if (self._deferredState === 1) {
  18. self._deferredState = 2;
  19. self._deferreds = [self._deferreds, deferred];
  20. return;
  21. }
  22. self._deferreds.push(deferred);
  23. return;
  24. }
  25. handleResolved(self, deferred);
  26. }
4 综合练习

对于注释的代码可以来回切换,看下结果。

</>复制代码

  1. function runAsync(){
  2. let p = new Promise(function(resolve,reject){
  3. console.log("exec");
  4. setTimeout(function(){
  5. resolve("someData");
  6. },2000);
  7. });
  8. return p;
  9. };
  10. function runAsync1(){
  11. return new Promise(function(resolve,reject){
  12. setTimeout(function(){
  13. console.log("异步1")
  14. // resolve("someData1");
  15. reject("error1")
  16. },2000);
  17. })
  18. };
  19. function runAsync2(){
  20. return new Promise(function(resolve,reject){
  21. setTimeout(function(){
  22. console.log("异步2")
  23. // resolve("someData2");
  24. reject("error2")
  25. },2000);
  26. })
  27. }
  28. var promise = runAsync();
  29. promise.then(function(data){
  30. console.log(data);
  31. return runAsync1()
  32. }).then(function(data){
  33. console.log(data);
  34. return runAsync2()
  35. }).then(function(data){
  36. console.log(data);
  37. // return "someData3"
  38. }).catch(function(error){
  39. console.log(error)
  40. })
  41. console.log("同步执行");
  42. console.log(promise);

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

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

相关文章

  • vue.js源码 - 剖析observer,dep,watch三者关系 如何具体的实现数据双向绑定

    摘要:双向数据绑定的核心和基础是其内部真正参与数据双向绑定流程的主要有和基于和发布者订阅者模式,最终实现数据的双向绑定。在这里把双向数据绑定分为两个流程收集依赖流程依赖收集会经过以上流程,最终数组中存放列表,数组中存放列表。 Vue双向数据绑定的核心和基础api是Object.defineProperty,其内部真正参与数据双向绑定流程的主要有Obderver、Dep和Watcher,基于d...

    mo0n1andin 评论0 收藏0
  • 剖析 React 源码:render 流程(一)

    摘要:大家可以看到是构造函数构造出来的,并且内部有一个对象,这个对象是本文接下来要重点介绍的对象,接下来我们就来一窥究竟吧。在构造函数内部就进行了一步操作,那就是创建了一个对象,并挂载到了上。下一篇文章还是流程相关的内容。这是我的剖析 React 源码的第二篇文章,如果你没有阅读过之前的文章,请务必先阅读一下 第一篇文章 中提到的一些注意事项,能帮助你更好地阅读源码。 文章相关资料 React ...

    hiYoHoo 评论0 收藏0
  • 剖析 React 源码:render 流程(二)

    摘要:就是,如果你不了解这个的话可以阅读下相关文档,是应用初始化时就会生成的一个变量,值也是,并且这个值不会在后期再被改变。这是我的剖析 React 源码的第三篇文章,如果你没有阅读过之前的文章,请务必先阅读一下 第一篇文章 中提到的一些注意事项,能帮助你更好地阅读源码。 文章相关资料 React 16.8.6 源码中文注释,这个链接是文章的核心,文中的具体代码及代码行数都是依托于这个仓库 热身...

    My_Oh_My 评论0 收藏0

发表评论

0条评论

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