如何在Cypress中使用PerformanceObserver?当前无法触发回调
在Cypress中使用PerformanceObserver捕获Longtask的解决方案
你的Cypress代码无法触发PerformanceObserver回调,主要是注册时机过晚、缺少等待逻辑和作用域问题导致的,以下是修正后的实现方案,和你Playwright的逻辑保持一致:
方案一:提前注册Observer(推荐)
利用cy.visit的onBeforeLoad钩子,在页面加载前就注册PerformanceObserver,确保不会错过初始化阶段的longtask:
cy.visit('你的目标网站URL', { onBeforeLoad(win) { // 挂载到window对象,避免作用域丢失 win.__totalBlockingTime = 0; const observer = new win.PerformanceObserver((list) => { const entries = list.getEntries(); entries.forEach(entry => { if (entry.entryType === 'longtask') { // 按照标准TBT计算规则,累加超过50ms的部分 win.__totalBlockingTime += Math.max(entry.duration - 50, 0); } }); }); observer.observe({ entryTypes: ['longtask'], buffered: true }); } }) // 等待足够时间确保所有longtask被捕获,可根据页面情况调整时长 .wait(5000) .window() .then(win => { const totalBlockingTime = win.__totalBlockingTime; console.log('总阻塞时间(TBT):', totalBlockingTime); // 可添加断言逻辑 expect(totalBlockingTime).to.be.a('number'); });
方案二:用Promise包裹等待逻辑
和Playwright的实现逻辑更接近,在cy.window()中返回Promise,让Cypress自动等待结果:
cy.window().then(win => { return new Promise(resolve => { let totalBlockingTime = 0; const observer = new win.PerformanceObserver((list) => { const entries = list.getEntries(); entries.forEach(entry => { if (entry.entryType === 'longtask') { totalBlockingTime += Math.max(entry.duration - 50, 0); } }); }); observer.observe({ entryTypes: ['longtask'], buffered: true }); // 超时后返回结果并断开观察者 setTimeout(() => { observer.disconnect(); resolve(totalBlockingTime); }, 5000); }); }).then(totalBlockingTime => { console.log('总阻塞时间(TBT):', totalBlockingTime); // 断言或其他处理 });
原代码失效的核心原因
- 注册时机滞后:如果在
cy.visit完成后才注册Observer,页面加载过程中产生的longtask已经触发,buffered: true可能无法回溯捕获(受浏览器实现和Cypress页面加载流程影响)。 - 缺少等待机制:Cypress是异步命令队列,原代码注册完Observer后没有等待回调触发或超时,导致无法获取到计算结果。
- 作用域问题:外部变量
totalBlockingTime在Cypress异步回调中被修改,但后续没有代码读取该值,且Cypress的作用域隔离可能导致值无法正确捕获。
内容的提问来源于stack exchange,提问作者Mark Hetherington
相关产品推荐
相关产品推荐

