这篇文章主要介绍“EventLoop如何测试Node或页面的性能”,在日常操作中,相信很多人在EventLoop如何测试Node或页面的性能问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”EventLoop如何测试Node或页面的性能”的疑惑有所帮助!接下来,请跟着小编一起来学习吧! Event Loop 机制大家应该都有了解。我先重复总结一下。Node.js 和 Javascript 的 Event Loop 不太一样,直观上是多了 setImmediate
和 process.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 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
的。如果同时启动 setImmediate
和 setTimeout
的 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中,如果一个元素没有设…