You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Puppeteer page.evaluate获取CLS值,无法在浏览器上下文外使用

问题描述

我正在使用page.evaluate在浏览器中记录每个CLS条目,并尝试将其保存到可在浏览器上下文外使用的变量中,代码如下:

page.exposeFunction('getCLSEntries', list => {
  //console.log("list:", list);
  let clsList = JSON.parse(list);
  return clsList;
});
console.log("CLS List:", clsList);

let cls = new Map();
while (scrollCount < maxScrolls) {
    //console.log("Function exposed")
    
    cls[scrollCount] = await page.evaluate(() => {
        console.log("reportCLSInstances called");
        let clsEntries = [];
        let clsInstances = [];
        const internalCLSInstances = (list) => {
            clsEntries = list.getEntries();
            const entries = JSON.stringify(clsEntries);
            window.getCLSEntries(entries).then((value) => {
                clsInstances.push(value);
                console.log("value: ", value);
            });
            console.log("CLS Instances 1:", clsInstances);
        };
        const observer = new PerformanceObserver(internalCLSInstances);
        observer.observe({type: 'layout-shift', buffered: true});
        console.log("CLS Instances 2:", clsInstances);
        return clsInstances;
    });
    console.log("CLS: ", cls);

但每次page.evaluate都返回[],即便返回前的日志显示数组已填充。当我将返回值改为["hello"]时,却能正常填充Map。请问我哪里操作有误?

问题原因与解决方案
  • 核心问题:异步逻辑未同步等待
    PerformanceObserver的回调是异步触发的,你在page.evaluate中直接同步返回clsInstances时,回调还没执行,数组自然为空。另外,window.getCLSEntries是异步函数(exposeFunction暴露的函数本质返回Promise),你在回调里调用它却未等待,即便回调触发,push操作也在then中异步执行,返回时数组依然是空的。

  • 修复方案

    1. 将浏览器上下文内的逻辑包装为Promise,等待CLS条目收集完成后再返回结果:
      cls.set(scrollCount, await page.evaluate(async () => {
          return new Promise(resolve => {
              const clsInstances = [];
              const handleCLSEntries = (list) => {
                  const entries = list.getEntries();
                  clsInstances.push(...entries);
                  // 若仅需获取缓冲的历史条目,收集后直接resolve
                  resolve(clsInstances);
                  // 若需持续监听实时偏移,可设置结束条件(如等待滚动停止、延迟一段时间)后再resolve
              };
              const observer = new PerformanceObserver(handleCLSEntries);
              observer.observe({type: 'layout-shift', buffered: true});
          });
      }));
      
    2. 移除冗余的exposeFunction:page.evaluate支持直接返回可JSON序列化的对象,无需通过暴露函数来回传数据,直接在浏览器上下文收集条目后返回即可,避免异步嵌套问题。
    3. 修正Map的使用方式:你当前用cls[scrollCount]是给对象添加属性,并非Map的正确操作,应使用cls.set(scrollCount, 结果)来添加键值对。

内容的提问来源于stack exchange,提问作者as07

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 09:33:11