10

我正在像这样进行 fetch 调用,fetch("foo.com/x.json")并希望获得在开发工具中报告的发出请求所需的时间。

我已经试过了,

performance.mark("fetch-start");
let start = performance.now();
let res = fetch("https://example.com/foo.json", {});
res.then(r => {
  performance.mark("fetch-end");
  performance.measure("fetch", "fetch-start", "fetch-end");
  var measures = performance.getEntriesByName("fetch");
  var measure = measures[0];
  console.log(measure);
});

也尝试过performance.now() -start,但它们不如 devtools 准确,我猜这是因为浏览器一次做不止一件事,并且不会把所有时间都花在孤立地测量事物上。

有没有办法像开发人员工具一样准确地进行网络计时?

4

5 回答 5

5

定义了一个Resource Timing API 来帮助我们做到这一点。
请注意,这仍然是一个草案,未来可能会发生变化,但它已经在三个主要浏览器引擎中可用。

const url = "https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png?" + Math.random();
// create PerformanceObserver
const resourceObserver = new PerformanceObserver( (list) => {
  list.getEntries()
    // get only the one we're interested in
    .filter( ({ name }) => name === url )
    .forEach( (resource) => {
      console.log( resource );
    } );
  // Disconnect after processing the events.
  resourceObserver.disconnect();
} );
// make it a resource observer
resourceObserver.observe( { type: "resource" } );
// start the new request
fetch( url, { mode: "no-cors" } );

于 2021-03-30T05:40:45.327 回答
3

回答:

尝试将下面的代码包装在异步函数中并使用 performance.now()


浏览器 JavaScript

async function checkResponseTime(testURL) {
    let time1 = performance.now();
    await fetch(testURL);
    let time2 = performance.now();
    return time2 - time1;
}
console.log(await checkResponseTime('https://stackoverflow.com'))

节点.JS

let fetch = require('node-fetch');
async function checkResponseTime(testURL) {
    let time1 = performance.now();
    await fetch(testURL);
    let time2 = performance.now();
    return time2 - time1;
}
console.log(await checkResponseTime('https://stackoverflow.com'))
于 2021-03-12T21:10:06.253 回答
2

在开发工具方面,您永远不会在 JS 领域获得始终如一的准确结果。

有时会在 JS 领域中获得关于用户感知的一致准确的结果。

我的意思是两个方面:

  • DevTools 测量获取资源的网络时间
  • JS土地测量网络时间+加载+资源完全可用时切换回JS

可以做一个简单的实验:

performance.mark("fetch-start");
const start = performance.now();
const res = fetch("https://example.com/foo.json", {});
res.then(measure).catch(measure);

someHeavyOperation();

function measure(r) {
  performance.mark("fetch-end");
  performance.measure("fetch", "fetch-start", "fetch-end");
  var measures = performance.getEntriesByName("fetch");
  var measure = measures[0];
  console.log(measure);
}

function someHeavyOperation() {
    /* block for 60 seconds! */
    const target = Date.now() + 60*1000;
    for (;;) {
        if (Date.now() > target) {
            break;
        }
    }
}

您可以替换someHeavyOperation为计算机上发生的许多事情,包括但不限于:

  • 页面上的其他JS代码
  • 正在更新的渲染
  • 此测量处于空闲背景选项卡中
  • 其他一些与浏览器无关的进程阻塞了 CPU
  • 浏览器,将结果加载到内存并提供给 JS
  • 任何组合或所有这些完美和谐地结合在一起,阻碍了您的测量

PS:您可以通过尝试加载一个非常大(且嵌套)的 JSON 文件来测试 JS 切换时间。JSON.parse在大字符串上应注意类似的延迟。

于 2021-03-14T03:11:02.850 回答
1

您的问题假设您在 DevTools 中看到的内容是准确的。这可能是一个有根据的事实,也可能是一个尚未得到证实的假设。我不会尝试接近 Dev Tools 中看到的值,因为无论我如何接近 Dev Tools 的测量值,我的结果充其量与 Dev Tools 的测量值一样准确。

因此,我将在本地托管一个代理,它将捕获从浏览器到给定站点的所有请求并传递给服务器,然后获取服务器的响应并将其发送到浏览器。使用此代理的唯一原因是记录从浏览器接收到的请求传递到服务器与响应到达的时间之间的时间。这将是一种非常准确的监控时间的方法,它会让你不受 DevTools 可能出现的问题的影响。一般来说,我不会费心这样做,因为我所做的测量已经足够好,但如果你想要一流的精度,那么我推荐这种方法。

于 2021-03-14T02:17:07.300 回答
1

也许可以接受使用 Node.js通过CPD调用 DevTools API并检索 DevTools 时间?

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch()
  const page = await browser.newPage()
  await page.goto('https://page-to-test')

  const resourceTimingJson = await page.evaluate(() =>
    JSON.stringify(window.performance.getEntriesByType('resource')))

  const resourceTiming = JSON.parse(resourceTimingJson)
  const fetchResourceTiming = resourceTiming.find(element => element.initiatorType.includes('fetch'))

  console.log(fetchResourceTiming)

  await browser.close()
})()

受此链接启发的 JScript

编辑:添加一个专注于持续时间的脚本:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch()
  const page = await browser.newPage()
  await page.goto('https://page-to-test')

  const resourceTimingJson = await page.evaluate(() =>
    JSON.stringify(window.performance.getEntriesByType('resource')))

  const resourceTiming = JSON.parse(resourceTimingJson)
  const fetchResourceTimingAll = resourceTiming.filter(element => element.initiatorType.includes('fetch'));
  if (fetchResourceTimingAll) { fetchResourceTimingAll.forEach( element=>console.log(element.name+" : "+element.duration)) }

  await browser.close()
})()
于 2021-03-17T17:19:34.523 回答