定时特定的提取调用

时间:2018-08-21 16:34:10

标签: javascript browser fetch-api

我正在像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准确,我猜这是由于浏览器一次执行多项操作并且没有花费所有时间进行测量而造成的隔离的东西。

有没有一种方法可以像Developer一样精确地用于网络计时?

5 个答案:

答案 0 :(得分:1)

答案:

尝试将下面的代码包装在异步函数中并使用 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'))

Node.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'))

答案 1 :(得分:1)

您将永远在 JS 领域获得关于开发工具的一致准确的结果。

您将可能在 JS 领域获得关于用户感知的一致准确的结果。

我的意思是两个方面:

  • DevTools 测量获取资源的网络时间
  • JS 土地在资源完全可用时测量网络时间 + 加载 + 移交给 JS

可以做一个简单的实验:

performance.mark("fetch-start");
const start = performance.now();
const 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);
});

someHeavyOperation();

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

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

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

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

答案 2 :(得分:1)

定义了一个 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" } );

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

也许可以接受使用 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()
})()

this link 启发的 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()
})()