当前位置: 首页 > news >正文

什么是EventLoop?怎么测试Node或页面的性能

Event Loop 机制大家应该都有了解。本文利用 EventLoop 去做一个有趣的检测node或页面性能的代码,顺便介绍了一下EventLoop,希望对大家有所帮助!

 

 

Event Loop

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,这样我们大致就能知道代码中同步的代码的执行情况。

测试函数

class MacroTaskChecker {constructor(macroTaskDispatcher, count = 1000, cb = () => { }) {this.macroTaskDispatcher = macroTaskDispatcherthis.COUNT = countthis.cb = cb}start(cb) {this.cb = cb || this.cbthis.stop = falseconst scope = () => {let count = this.COUNTconst startTime = performance.now()const fn = () => {count--if (count > 0) this.macroTaskDispatcher(fn)else {const endTime = 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}
}

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

function meaninglessRun(time) {console.time('meaninglessRun')for (let i = time; i--; i > 0) {// do nothing}console.timeEnd('meaninglessRun')
}
setTimeout(() => {meaninglessRun(1000 * 1000 * 1000)
}, 1000 * 5)
setTimeout(() => {checker.stop()console.log('stop')
}, 1000 * 20)

 setTimeout

const checker = new MacroTaskChecker(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.47 avg: 825.14
time: 4958.18 avg: 829.83
meaninglessRun: 918.626ms
time: 6001.69 avg: 95.95
time: 6125.72 avg: 817.18
time: 6285.07 avg: 635.16
// browse
time: 153529.90 avg: 205.21
time: 154023.40 avg: 204.46
meaninglessRun: 924.463ms
time: 155424.00 avg: 71.62
time: 155908.80 avg: 208.29
time: 156383.70 avg: 213.04

 

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

setImmediate

如果使用 node.js 的 setImmediate

const checker = new MacroTaskChecker(setImmediate, 1000 * 10)

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

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

 

按照 Node.js 文档中的解释,setImmediate 会在每一个 loop (phase) 的 check 阶段执行。使用 setImmediate 应该是能准确记录每一次 Loop 的。我这台机器大概是 40000 到 60000 之间的循环次数。

window.postMessage

在 browser 上由于没有 setImmediate 我们可以按照 MDN 上的指引使用 window.postMessage 实现一个。

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

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

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

 

MessageChannel

browser

理论上 browser 使用 MessageChannel 应该也是可以的,还避免了无效的消息被其他 window.addEventListener("message", handler) 接收:

const { port1, port2 } = new MessageChannel();
const fns = []
port1.onmessage = () => {const currentFns = [...fns]fns.length = 0currentFns.forEach(fn => fn())
};
function messageChannelMacroTaskDispatcher(fn) {fns.push(fn)port2.postMessage(1)
}

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

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

 

node

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

mc time: 460.99 avg: 353930.80
mc time: 489.52 avg: 355088.11
mc time: 520.30 avg: 326384.64
mc time: 551.78 avg: 320427.29

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

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

 

很明显跟不是宏任务了。我猜测 MessageChannel 在 node.js 被归入到跟 socket 等同级别了,就是超出阈值之后的任务会移动到下一个loop中。

总结

使用这种方式去检测性能还挺有趣的,正式使用的话这个指标感觉过于不稳定(即使什么都没做都会有20%-30%的振动)。推荐和其他正经的办法(比如 performance 等)结合。

同时这种方式非常有可能影响正常的 Event Loop,比如 Node.js 中会有一个 pull 的阶段,在执行完全部微任务后,没有任何 timer 的话是会停留在这个阶段,准备马上执行下一个出现的微任务。

顺便复习了下 Event Loop。没想到的是 MessageChannel 在两边的差距居然有这么大。

相关文章:

什么是EventLoop?怎么测试Node或页面的性能

Event Loop 机制大家应该都有了解。本文利用 EventLoop 去做一个有趣的检测node或页面性能的代码,顺便介绍了一下EventLoop,希望对大家有所帮助! Event Loop Event Loop 机制大家应该都有了解。我先重复总结一下。 Node.js 和 Javascript 的…...

1018 锤子剪刀布 1025 反转链表

现给出两人的交锋记录,请统计双方的胜、平、负次数,并且给出双方分别出什么手势的胜算最大。 输入格式: 输入第 1 行给出正整数 N(≤10 5 ),即双方交锋的次数。随后 N 行,每行给出一次交锋的信…...

卷积神经网络的原理及实现

专栏:神经网络复现目录 卷积神经网络 本章介绍的卷积神经网络(convolutional neural network,CNN)是一类强大的、为处理图像数据而设计的神经网络。 基于卷积神经网络架构的模型在计算机视觉领域中已经占主导地位,当今…...

【C++知识点】重载

✍个人博客:https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 📚专栏地址:C/C知识点 📣专栏定位:整理一下 C 相关的知识点,供大家学习参考~ ❤️如果有收获的话,欢迎点赞👍…...

apscheduler三种定时触发方式

#第一种# date: 特定的时间点触发# 2019-01-01 00:00:00 准时执行# import time # from apscheduler.schedulers.blocking import BlockingScheduler # # def my_job(): # print(time.strftime(%Y-%m-%d %H:%M:%S, time.localtime(time.time()))) # sched BlockingSchedu…...

802.11 service服务类型

802.11 serviceservice定义service分类按照模块分为两类按照功能分为六类数据传输相关服务分布式服务DS(Distribution Service)整合服务IS(Integration Service)关联(association)重关联(reasso…...

pytest测试框架——allure报告

文章目录一、allure的介绍二、allure的运行方式三、allure报告的生成方式一、在线报告、会直接打开默认浏览器展示当前报告方式二、静态资源文件报告(带index.html、css、js等文件),需要将报告布置到web服务器上。四、allure中装饰器1、实现给…...

SQLI-Labs(3)8-14关【布尔盲注和时间盲注】

目录 第八关 第九关: 第十关 第十一关 第十二关 第十三关 第十四关 第八关 我们用测试语句来测试是否为注入点 从上图中得知存在注入点,那么接下来就是爆列 一共有三列,接下来用union select 和报错注入都试一下发现没有回显点&…...

ESP32学习笔记03-日志打印

ESP32日志 日志分为5个等级 ESP_LOGE - error (lowest)ESP_LOGW - warningESP_LOGI - infoESP_LOGD - debugESP_LOGV - verbose (highest)API 0.头文件 #include "esp_log.h"1.给一个日志标签设置等级...

mongoTemplate非string类型模糊查询

需求 为方便使用人员对任务Task的搜索,需要根据number实现模糊搜索。 背景 之前设计的number是long类型,但是mongodb只支持string类型的正则匹配。 方案 修改number为string类型;新增一个冗余字段,用于模糊查询;在…...

Redis是单线程还是多线程?Redis的10种数据类型,有哪些应用场景?

目录专栏导读一、同样是缓存,用map不行吗?二、Redis为什么是单线程的?三、Redis真的是单线程的吗?四、Redis优缺点1、优点2、缺点五、Redis常见业务场景六、Redis常见数据类型1、String2、List3、Hash4、Set5、Zset6、BitMap7、Bi…...

到底什么才是幻读?

💗推荐阅读文章💗 🌸JavaSE系列🌸👉1️⃣《JavaSE系列教程》🌺MySQL系列🌺👉2️⃣《MySQL系列教程》🍀JavaWeb系列🍀👉3️⃣《JavaWeb系列教程》…...

RPC重试机制和控制方案

重试机制 因为网络抖动等原因导致 RPC 调用失败,这时候使用重试机制可以提高请求的最终成功率,减少故障影响,让系统运行更稳定。 重试简易实现方案 在重试的过程中,为了能够在约定的时间内进行安全可靠地重试,在每次…...

【无标题】动态给结构体赋值

#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { int id; char name[20]; double score; } Student; int main() { Student *p (Student *)malloc(sizeof(Student)); if (p NULL) { printf(“Memory allocation failed.”…...

centos7 soft raid每周自动同步的问题

之前redhat老版本时也遇到过这样的问题https://blog.csdn.net/jolly10/article/details/108768360centos7解决的办法略有不同&#xff0c;记录一下&#xff1a;centos7默认是每周日凌晨1点进行raid检查&#xff0c;有点太频繁了[oracleqht117 data]$ ls /etc/cron*/etc/cron.de…...

嵌入式Linux内核代码风格

这是一个简短的文档&#xff0c;描述了linux内核的首选代码风格。代码风格是因人而异的&#xff0c;而且我 不愿意把我的观点强加给任何人&#xff0c;不过这里所讲述的是我必须要维护的代码所遵守的风格&#xff0c; 并且我也希望绝大多数其他代码也能遵守这个风格。请在写代码…...

Andorid:关于Binder几个面试问题

1.简单介绍下binderbinder是一种进程间通讯的机制进程间通讯需要了解用户空间和内核空间每个进程拥有自己的独立虚拟机&#xff0c;系统为他们分配的地址空间都是互相隔离的。如两个进程需要进行通讯&#xff0c;则需要使用到内核空间做载体&#xff0c;内核空间是所有进程共享…...

【剑指Offer-Java】包含min函数的栈?

题目 定义栈的数据结构&#xff0c;请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中&#xff0c;调用 min、push 及 pop 的时间复杂度都是 O(1)。 MinStack minStack new MinStack(); minStack.push(-2); minStack.push(0); minStack.push(-3); minStack.min()…...

红队APT——邮件钓鱼攻击SwaksOffice漏洞RLO隐藏压缩释放

目录 (一)采用自己搭建Ewomail配合Swaks 0x01 搭建过程 0x02 配置转发信息 (二)网页钓鱼-克隆修改...

【Java|基础篇】超详细讲解运算符

文章目录1. 什么是运算符2. 算术运算符隐式类型转换强制类型转换字符串的拼接字符相加自增和自减运算符3.赋值运算符4. 关系运算符5. 逻辑运算符短路与(&&)和短路或(||)6.三目运算符7. 位运算符8. 移位运算1. 什么是运算符 运算符用于执行程序代码运算&#xff0c;会针…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

css实现圆环展示百分比,根据值动态展示所占比例

代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

从零实现富文本编辑器#5-编辑器选区模型的状态结构表达

先前我们总结了浏览器选区模型的交互策略&#xff0c;并且实现了基本的选区操作&#xff0c;还调研了自绘选区的实现。那么相对的&#xff0c;我们还需要设计编辑器的选区表达&#xff0c;也可以称为模型选区。编辑器中应用变更时的操作范围&#xff0c;就是以模型选区为基准来…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

基于Uniapp开发HarmonyOS 5.0旅游应用技术实践

一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架&#xff0c;支持"一次开发&#xff0c;多端部署"&#xff0c;可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务&#xff0c;为旅游应用带来&#xf…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...