当我们在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(回调),或任何其他方式来实现这一点?
答案 0 :(得分:5)
这是因为你有一个繁忙的循环,显然需要比你的计时器更长的时间:
cnt = 10**9
--cnt while cnt > 0
node.js中的Javascript是单线程和事件驱动的。它一次只能做一件事,它将完成当前正在做的事情,然后才能为setTimeout()
发布的事件提供服务。因此,如果您的繁忙循环(或任何其他长时间运行的Javascript代码)花费的时间比您设置的计时器要长,那么在完成其他Javascript代码之前,计时器将无法运行。 “单线程”意味着node.js中的Javascript一次只做一件事,它等待一件事将控制权返回给系统,然后才能为下一个等待运行的事件提供服务。
所以,这是代码中的事件序列:
setTimeout()
从现在开始计划100秒的计时器回调。setTimeout()
计时器在JS实现内部触发,并将事件插入到Javascript事件队列中。该事件目前无法运行,因为JS解释器仍在运行繁忙的循环。setTimeout()
回调。.then()
处理程序被调用的承诺。注意:由于Javascript的单线程和事件驱动特性,Javascript中的计时器无法保证在您安排它们时完全被调用。它们将尽可能接近执行,但如果其他代码在它们触发时运行,或者如果它们在您之前的事件队列中有很多项目,则该代码必须在计时器回调实际执行之前完成。
那么如果我们想知道Promise何时实际解决了,怎么样?
当繁忙的循环完成后,承诺得以解决。它完全没有在100ms点解决(因为你的繁忙循环显然需要超过100ms才能运行)。如果您想确切知道承诺何时解决,您只需在setTimeout()
回调权限内登录resolve()
。这将告诉你确切的时间何时解决,尽管它与你现在登录的地方几乎相同。延迟的原因是繁忙的循环。
根据您的评论,您似乎想以某种方式确切地衡量在Promise中实际调用resolve()
的时间,但您说您无法修改getData()
中的代码。你不能直接这样做。正如您所知,您可以测量调用.then()
处理程序的时间,这可能会在resolve()
被调用后不超过几毫秒。
您可以使用自己的实现替换promise基础结构,然后您可以直接检测resolve()
回调,但替换或挂钩promise实现可能会影响事件的时间,而不仅仅是{{1处理程序。
所以,在我看来,你刚刚过度约束了这个问题。您想要测量某些代码内部发生的事情,但是您不允许在该代码中使用任何检测。这只剩下两个选择:
.then()
。resolve()
时进行衡量。第一个选项可能有一个heisenberg不确定性问题,因为如果你替换或挂钩promise实现,你可能会比你应该做的更多地影响时间。
第二个选项测量在实际.then()
之后稍微发生的事件。选择哪一个听起来最接近你真正想要的。