如何知道在Node.js中实际解决Promise的时间?

时间:2016-12-11 16:24:10

标签: node.js promise es6-promise

当我们在nodejs中使用Promise时,给定Promise p,我们无法通过在“then”回调中记录currentTime来知道Promise p何时被实际解析。

为了证明这一点,我在下面编写了测试代码(使用CoffeeScript):

# the procedure we want to profile
getData = (arg) ->
    new Promise (resolve) ->
        setTimeout ->
            resolve(arg + 1)
        , 100

# the main procedure
main = () ->
    beginTime = new Date()
    console.log beginTime.toISOString()
    getData(1).then (r) ->
        resolveTime = new Date()
        console.log resolveTime.toISOString()
        console.log resolveTime - beginTime
    cnt = 10**9
    --cnt while cnt > 0
    return cnt

main()

运行上面的代码时,您会注意到resolveTime(代码运行到回调函数的时间)远远超过了beginTime的100ms。

那么如果我们想知道Promise何时实际解决了,怎么样?

我想知道确切的时间,因为我正在通过记录进行一些分析。当我在黑盒子外面进行一些分析时,我无法修改Promise p的实现。

那么,是否有一些函数,如promise.onUnderlyingConditionFulfilled(回调),或任何其他方式来实现这一点?

1 个答案:

答案 0 :(得分:5)

这是因为你有一个繁忙的循环,显然需要比你的计时器更长的时间:

cnt = 10**9
--cnt while cnt > 0

node.js中的Javascript是单线程和事件驱动的。它一次只能做一件事,它将完成当前正在做的事情,然后才能为setTimeout()发布的事件提供服务。因此,如果您的繁忙循环(或任何其他长时间运行的Javascript代码)花费的时间比您设置的计时器要长,那么在完成其他Javascript代码之前,计时器将无法运行。 “单线程”意味着node.js中的Javascript一次只做一件事,它等待一件事将控制权返回给系统,然后才能为下一个等待运行的事件提供服务。

所以,这是代码中的事件序列:

  1. 调用setTimeout()从现在开始计划100秒的计时器回调。
  2. 然后你进入繁忙的循环。
  3. 当它处于繁忙循环中时,setTimeout()计时器在JS实现内部触发,并将事件插入到Javascript事件队列中。该事件目前无法运行,因为JS解释器仍在运行繁忙的循环。
  4. 然后最终完成忙循环并将控制权返回给系统。
  5. 完成后,JS解释器会检查事件队列以查看是否有其他事件需要服务。它找到了timer事件,因此它会处理它并调用setTimeout()回调。
  6. 该回调解析了触发.then()处理程序被调用的承诺。
  7. 注意:由于Javascript的单线程和事件驱动特性,Javascript中的计时器无法保证在您安排它们时完全被调用。它们将尽可能接近执行,但如果其他代码在它们触发时运行,或者如果它们在您之前的事件队列中有很多项目,则该代码必须在计时器回调实际执行之前完成。

      

    那么如果我们想知道Promise何时实际解决了,怎么样?

    当繁忙的循环完成后,承诺得以解决。它完全没有在100ms点解决(因为你的繁忙循环显然需要超过100ms才能运行)。如果您想确切知道承诺何时解决,您只需在setTimeout()回调权限内登录resolve()。这将告诉你确切的时间何时解决,尽管它与你现在登录的地方几乎相同。延迟的原因是繁忙的循环。

    根据您的评论,您似乎想以某种方式确切地衡量在Promise中实际调用resolve()的时间,但您说您无法修改getData()中的代码。你不能直接这样做。正如您所知,您可以测量调用.then()处理程序的时间,这可能会在resolve()被调用后不超过几毫秒。

    您可以使用自己的实现替换promise基础结构,然后您可以直接检测resolve()回调,但替换或挂钩promise实现可能会影响事件的时间,而不仅仅是{{1处理程序。

    所以,在我看来,你刚刚过度约束了这个问题。您想要测量某些代码内部发生的事情,但是您不允许在该代码中使用任何检测。这只剩下两个选择:

    1. 替换承诺实施,以便您可以直接审核.then()
    2. 在触发resolve()时进行衡量。
    3. 第一个选项可能有一个heisenberg不确定性问题,因为如果你替换或挂钩promise实现,你可能会比你应该做的更多地影响时间。

      第二个选项测量在实际.then()之后稍微发生的事件。选择哪一个听起来最接近你真正想要的。