分享更有价值
被信任是一种快乐

EventLoop如何测试Node或页面的性能

文章页正文上

这篇文章主要介绍“EventLoop如何测试Node或页面的性能”,在日常操作中,相信很多人在EventLoop如何测试Node或页面的性能问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”EventLoop如何测试Node或页面的性能”的疑惑有所帮助!接下来,请跟着小编一起来学习吧! Event Loop 机制大家应该都有了解。我先重复总结一下。Node.js 和 Javascript 的 Event Loop 不太一样,直观上是多了 setImmediateprocess.nextTick 两个 API。其次是由于运行时不一样,Html Standrad 里面会考虑多页面、DOM操作等不同来源会有不同的 task queue 。而 Node.js Event Loop 中需要考虑的没这么多。按照我的理解,双方在概念上是一致的,可以如此概括(或者看这里):task queue 任务队列。一些事件等会被定义为任务,很多时候会被称为 MacroTask(宏任务)与 MicroTask 进行对应。每次会获取队头的 task 进行执行。microtask queue 微任务队列。会有一个微任务队列,一个 Task 内一般会执行清空微任务队列。如此往复。在上面的了解之后,有一个简单的对性能进行测量的方法:每秒内完成了多少次 Event Loop 循环,或者说执行了多少个 MacroTask,这样我们大致就能知道代码中同步的代码的执行情况。测试函数

classMacroTaskChecker{
constructor(macroTaskDispatcher,count=1000,cb=()=>{}){
this.macroTaskDispatcher=macroTaskDispatcher
this.COUNT=count
this.cb=cb
}
start(cb){
this.cb=cb||this.cb
this.stop=false
constscope=()=>{
letcount=this.COUNT
conststartTime=performance.now()
constfn=()=>{
count--
if(count>0)this.macroTaskDispatcher(fn)
else{
constendTime=performance.now()
//执行COUNT次宏任务之后计算平均每秒执行了多少个
this.cb({
avg:this.COUNT/(endTime-startTime)*1000,
timestamp:endTime
})
!this.stop&&this.macroTaskDispatcher(scope)
}
}
this.macroTaskDispatcher(fn)
}
scope()
}

stop(){
this.stop=true
}
}

之后,执行一些死循环去测试是否能检测到密集同步代码执行。

functionmeaninglessRun(time){
console.time('meaninglessRun')
for(leti=time;i--;i>0){
//donothing
}
console.timeEnd('meaninglessRun')
}

setTimeout(()=>{
meaninglessRun(1000*1000*1000)
},1000*5)

setTimeout(()=>{
checker.stop()
console.log('stop')
},1000*20)

setTimeout

constchecker=newMacroTaskChecker(setTimeout,100)

checker.start(v=>console.log(`time:${v.timestamp.toFixed(2)}avg:${v.avg.toFixed(2)}`))

从输出中能明显看到同步阻塞的时候avg是下降的。不过在 browser 和 node.js 上测试两边会有明显差距。

//node.js
time:4837.47avg:825.14
time:4958.18avg:829.83
meaninglessRun:918.626ms
time:6001.69avg:95.95
time:6125.72avg:817.18
time:6285.07avg:635.16
//browser
time:153529.90avg:205.21
time:154023.40avg:204.46
meaninglessRun:924.463ms
time:155424.00avg:71.62
time:155908.80avg:208.29
time:156383.70avg:213.04

虽然达成我们的目的,但是使用 setTimeout 是不完全能准确记录下每一个任务的。根据 HTML Standrad 和 MDN 的说法,setTimeout 最少的会等待4ms。从这个角度看 browser avg * 4ms approx 1000ms。而 node.js 应该是没有遵循 browser 那边的约定,但是也没有执行到记录每一个loop。setImmediate如果使用 node.js 的 setImmediate

constchecker=newMacroTaskChecker(setImmediate,1000*10)

可以看到执行次数大概高出 Node.js setTimeout 一个量级:

time:4839.71avg:59271.54
time:5032.99avg:51778.84
meaninglessRun:922.182ms
time:6122.44avg:9179.95
time:6338.32avg:46351.38
time:6536.66avg:50459.77

按照 Node.js 文档中的解释,setImmediate 会在每一个 loop (phase) 的 check 阶段执行。使用 setImmediate 应该是能准确记录每一次 Loop 的。我这台机器大概是 40000 到 60000 之间的循环次数。window.postMessage在 browser 上由于没有 setImmediate 我们可以按照 MDN 上的指引使用 window.postMessage 实现一个。如果想在浏览器中实现 0ms 延时的定时器,你可以参考这里所说的 window.postMessage()

constfns=[]
window.addEventListener("message",()=>{
constcurrentFns=[...fns]
fns.length=0
currentFns.forEach(fn=>fn())
},true);
functionmessageChannelMacroTaskDispatcher(fn){
fns.push(fn)
window.postMessage(1)
}

可以看到和 node.js setImmediate 量级是一致的。

time:78769.70avg:51759.83
time:78975.60avg:48614.49
meaninglessRun:921.143ms
time:80111.50avg:8805.14
time:80327.00avg:46425.26
time:80539.10avg:47169.81

MessageChannel理论上 browser 使用 MessageChannel 应该也是可以的,还避免了无效的消息被其他 window.addEventListener("m免费云主机、域名essage", handler) 接收:

const{port1,port2}=newMessageChannel();
constfns=[]
port1.onmessage=()=>{
constcurrentFns=[...fns]
fns.length=0
currentFns.forEach(fn=>fn())
};
functionmessageChannelMacroTaskDispatcher(fn){
fns.push(fn)
port2.postMessage(1)
}

不是很懂为啥会比 window.postMessage 频繁一点,同时启动两个 checker 的话可以看到 log 是成对出现的,也就是说一个loop内大家都只执行了一次。我猜测是 window.postMessage 的实现方式消耗会大一些。

time:54974.80avg:68823.12
time:55121.00avg:68493.15
meaninglessRun:925.160888671875ms
time:56204.60avg:9229.35
time:56353.00avg:67430.88
time:56503.10avg:66666.67
//一起执行wp=window.postMessagemc=MessageChannel
wptime:43307.90avg:25169.90
mctime:43678.40avg:27005.13
wptime:43678.60avg:26990.55
mctime:44065.80avg:25833.12
wptime:44066.00avg:25819.78
mctime:44458.40avg:25484.20

在 node.js 上也有 MessageChannel ,是否也可以用来测量loop次数呢?

mctime:460.99avg:353930.80
mctime:489.52avg:355088.11
mctime:520.30avg:326384.64
mctime:551.78avg:320427.29

量级很不正常。理论上不应该超过 setImmediate 的。如果同时启动 setImmediatesetTimeout 的 checker:

...
(messagechannel)time:1231.10avg:355569.31
(messagechannel)time:1260.14avg:345825.77
(setImmediate)time:1269.95avg:339.27
(setTimeout)time:1270.09avg:339.13
(messagechannel)time:1293.80avg:298141.74
(messagechannel)time:1322.50avg:349939.04
...

很明显跟不是宏任务了。我猜测 MessageChannel 在 node.js 被归入到跟 socket 等同级别了,就是超出阈值之后的任务会移动到下一个loop中。到此,关于“EventLoop如何测试Node或页面的性能”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注云技术网站,小编会继续努力为大家带来更多实用的文章!

相关推荐: vue屏幕不能滑动问题怎么解决

本篇内容主要讲解“vue屏幕不能滑动问题怎么解决”免费云主机、域名,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“vue屏幕不能滑动问题怎么解决”吧! 屏幕不能滑动的原因可以分为两种情况:在Vue中,如果一个元素没有设…

文章页内容下
赞(0) 打赏
版权声明:本站采用知识共享、学习交流,不允许用于商业用途;文章由发布者自行承担一切责任,与本站无关。
文章页正文下
文章页评论上

云服务器、web空间可免费试用

宝塔面板主机、支持php,mysql等,SSL部署;安全高速企业专供99.999%稳定,另有高防主机、不限制内容等类型,具体可咨询QQ:360163164,Tel同微信:18905205712

主机选购导航云服务器试用

登录

找回密码

注册