最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • [JS杂谈(一)][Promise v8源码]群里Promise面试题

    正文概述 掘金(Nctdt)   2021-04-06   353

    群里看到,不懂就查,查不懂就对线源码。

    题目

    Promise.resolve().then(() => {
        console.log(0)
        return Promise.resolve(4)
    }).then(res => {
        console.log('res: ', res)
    })
    
    Promise.resolve().then(() => {
        console.log(1);
    }).then(() => {
        console.log(2);
    }).then(() => {
        console.log(3);
    }).then(() => {
        console.log(5);
    }).then(() =>{
        console.log(6);
    })
    

    输出

    1 2 3 4 5 6

    逻辑

    首先设1.then(() => { console.log(1) })这一个微任务,

    其他同理。

    一开始执行完两个Promise.resolve()以后:

    microTask: `0 1`
    

    Promise.resolve(4)返回一个状态为fulfilledPromise此时按逻辑应该把4加入到微任务中了,

    但是在then中返回fulfilled状态的Promise的话,

    Promise内部会将返回的Promisethen方法执行放入到微任务队列中执行。

    microTask: 1 Promise.resolve(4).then
    microTask: Promise.resolve(4).then 2
    

    then内部因为Promise.resolve(4)状态已经是fulfilled了,

    又申请了个微任务为了让0同步Promise.resolve(4).thenfulfilled的状态,

    因为需要等Promise.resolve(4).then内部暴露的Promise初始化完毕后再执行,

    所以需要一个微任务等待。

    (实际为:Promise.resolve(4).then返回的Promise需要一个微任务进行同步Promise.resolve(4)返回的Promisefulfilled状态,在同步时顺便也把外部0返回的Promise一并同步了)

    注:0返回的Promise是同步Promise.resolve(4).then的状态

    microTask: 2 同步状态
    microTask: 同步状态 3
    microTask: 3 4
    最后输出: 1 2 3 4 5 6
    

    证明 Then方法会放入微队列中

    0修改为

    .then(() => {
      console.log(0)
        // return Promise.resolve(4)
        return {
          then(resolve) {
          console.log('then')
          resolve(4)
        },
      }
    })
    
    输出:
    0
    1
    then
    2
    res:  4
    3
    5
    6
    

    可以看到then方法是放入了微任务队列中的。

    这个then方法中resolve执行直接同步fulfilled状态到0返回的Promise状态上,因此执行完then方法下一个微任务就是输出res了。

    源码

    我翻找了v84.3.65版本还未使用v8 Torque(tq v8内部语言)或C实现的promise.js的源码,在5版本以后就使用C实现了,最新版本使用tq实现。

    通过看源码可知Promise.resovle(x) 相当于new Promise(rs => rs(x)),两者行为一致,有兴趣可以试试。

    源码地址

    deferred

    首先介绍一下deferreddeferred指内部为了链式调用创建的对象,在then方法被调用时返回的就是deferredPromisedeferred对象也是个Promise(废话,不这样咋链式

    据上面源码可知Promise.then/返回Thenable都会创建这个对象。据我感觉最新返回Thenable并不会创建这个对象,直接使用外部的deferred对象

    function PromiseDeferred() {
      if (this === $Promise) {
        // Optimized case, avoid extra closure.
        var promise = PromiseInit(new $Promise(promiseRaw));
        return {
          promise: promise,
          resolve: function(x) { PromiseResolve(promise, x) },
          reject: function(r) { PromiseReject(promise, r) }
        };
      } else {
        var result = {};
          result.promise = new this(function(resolve, reject) {
          result.resolve = resolve;
          result.reject = reject;
        })
        return result;
      }
    }
    

    理解

    =>为返回,->为步骤,deferred Object简称为deferred

    注:之后的"同步状态"微任务只针对非pending状态

    then(onResolve) => deferred
    	-> onResolve => Promise(fulfilled)
    	-> Promise(fulfilled).then(deferred.resolve, deferred.reject)
    	-> 放入一个微任务"同步状态"到外部 deferred 上
    	-> 以便链式调用
    then(onResolve) => deferred
    	-> onResolve => Thenable
    	-> deferred.resolve(Thenable)
      -> then(onResolve).then(onResolve2, onReject2)
      	-> deferred.promise.then(onResolve2, onReject2)
      		-> 不调用这个 .then 据我理解是不会将 Thenable 对象转换成 defeerred 的
      	-> deferred.promise PromiseState is fulfilled
      	-> 执行 then 方法,onResolve2 在内部会被包装因此
          -> 执行中 Thenable 转换成 thenDeferred 时同步执行 then 方法
            -> 根据 then 方法执行后决定 thenDeferred.promise 状态
          -> thenDeferred.promise.then(onResolve, onReject)
            -> 挂载 deferred.promise.then 的参数到 thenDeferr.promise.then 上
    

    返回Thenable对象:

    Promise.resolve()
      .then(() => {
        console.log(0)
        return {
          then(resolve) { // 在4.x源码中这儿是同步执行
            console.log('then')
            resolve(4)
          },
        }
      })
      .then(res => {
        console.log('res: ', res)
      })
    相当于
    Promise.resolve()
      .then(() => {
        console.log(0)
      })
      .then(() => { // 在4.x源码中这儿是同步执行
        console.log('then')
        return 4
      })
      .then(res => {
        console.log('res: ', res)
      })
    

    这是在4.3.65版本的实现逻辑(我的理解,有误您对

    源码结论

    返回Promise都是需要一个微任务,但是Thenable又不需要,但是这是4.多的代码实现,之后代码改动很大,不过思路大体一致。(应该吧,我看不懂后面的了太菜了

    推测

    因为这是4.3.65的代码了,所以不符合之前推理的逻辑也正常,虽然这个版本的代码已经挺优雅了,但是可能为了更优雅的实现,Thenable/Promisethen要一视同仁,也得放进微任务中执行,没必要做特殊处理,所以两个的then方法都进入了微任务队列中处理。(我寻思挺合理的

    其次我的源码理解的返回Thenable对象的promise后面得再跟一个then方法才会执行Thenable.then,所以需要改动并统一行为。(可能是我理解错误?

    那么为什么在目前的版本就是返回Promise是要两个微任务,而Thenable还是一个

    讲道理

    据我推测在之后版本中,只要有Then都会放入微任务队列执行一下,如果是Promise

    同步状态其实相当于往一个promisethen方法传入(deferred.resolve, deferred.reject)简称这个行为为同步d

    不讨论rejected状态(或者说和 fulfilled状态差不多

    PromiseState is fulfilled/Thenable Object:
    	设 Promise.resolve().then() 返回的 deferred 为 d
    	Promise.resolve().then(() => Promise.resolve(4))
    		-> Promise.resolve(4) => Promise(fulfilled) 且非 deferred
    		-> 内部处理
    			-> 有 then 方法进行劫持放进微任务队列中执行
    			-> 由于 then 方法未传入参数, 默认为 onResolve = x => x
    			-> 即 Promise(fulfilled).then(x => x)
    			-> pending 状态需要同步
    			-> Promise(fulfilled).then(x => x).then(同步d)
    		-> 以上是按照 4.x 逻辑来的,不过 then 方法变成异步罢了
    	Promise.resolve().then(() => ({ then(rs) { rs(4) }})
    		-> Thenable 在微任务被调用 then 方法时内部会传入 d.resolve, d.reject 来直接同步外部,
    		-> 因此只需要一个微任务执行 then 方法即可
    新的内部实现应该比这优雅,但是可惜我看不懂
    Promise.resolve(4).then(res => res) -> PromiseState is pending:
    	将当前的promise.then中放入同步状态微任务,
    	以便可以同步状态到deferred对象上
    	比如:
        Promise.resolve().then(() => Promise.resolve(4).then(res => res))
        Promise.resolve().then() 返回的是 deferred(d)
        Promise.resolve(4).then(res => res) 返回的也是 deferred(thenD)
        因为需要同步状态,因此内部处理挂载上去
        Promise.resolve(4).then(res => res).then(同步d)
        以便d能及时更新状态
    

    根据

    前面代码改成

    Promise.resolve()
      .then(() => {
        console.log(0)
        return Promise.resolve(4).then(res => res) // pending 状态挂载同步状态微任务
      }).then(res => {
        console.log('res: ', res)
      })
    

    输出:0 1 2 3 4 5 6

    结语

    一时兴起,大胆猜测,人菜想写,如有错误,轻骂。

    内部实现写的好导致的结果,我反正信了。(doge


    起源地下载网 » [JS杂谈(一)][Promise v8源码]群里Promise面试题

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元