JavaScript页面渲染速度测试脚本实现原理分析

作者:听澜

时间:2026-10-28

浏览:239

本文分享并解析了一段用于检测JavaScript页面渲染速度的测试脚本。通过在HTML头部和尾部注入时间戳,计算页面加载耗时,并利用动态创建script标签提交数据至服务器。文章详细分析了page_speed_v2.js的核心逻辑,包括createScript方法构建隐藏脚本、submitDataForPageSpeed方法封装测速数据及defaultSubmit方法处理随机提交策略,旨在帮助开发者理解前端性能监控的实现机制。

文章目录

页面渲染速度测试脚本基础实现

具体实现代码如下所示:

该部分代码用于获取页面渲染开始时的时间戳,并将其初始化保存在PAGE_SPEED_TIME数组中。
<html><script type="text/javascript">/*tag*/PAGE_SPEED_TIME = [new Date().getTime()];</script><head>
......
</head>

页面底部的相关代码如下:

......
在页面最末端执行代码,用于计算整个页面加载所消耗的时间。
</body>
<script src="http://ossweb-img.qq.com/images/js/pagespeed/page_speed_v2.js"></script></html>

page_speed_v2.js核心逻辑解析

接下来对page_speed_v2.js文件的内容进行详细分析。为了便于阅读,对该脚本进行了重新格式化。

相关代码片段如下:

执行匿名函数以构建PageSpeed对象。
;(function() {
PageSpeed = {};/* 此处未使用var关键字,因此PageSpeed成为全局window对象的属性 */
动态创建Script标签机制/**
 * 绑定createScript方法
 *
 * @param String a script标签的src属性的值
 * @param String b script标签的id属性的值
 */
 PageSpeed.createScript = function(a, b) {
 var c = null;
if (document.getElementById(b)) { /* 若script标签已存在 */
 c = document.getElementById(b)
 } else { /* 若不存在,则创建新的script标签 */
 c = document.createElement('script');
 var d = null;
 if (document.getElementsByTagName) {
 d = document.getElementsByTagName('head')[0] || document.documentElement;
 } else {
 d = document.documentElement;
 }
 d.insertBefore(c, d.firstChild); /* 调用insertBefore方法,将新创建的script标签插入为第一个子元素 */
 }
/* 此处的大括号用于代码片段分组 */
 {
 c.setAttribute('type', 'text/html');
 c.setAttribute('style', 'display:none;');
 c.setAttribute('charset', 'gb2312');
 c.setAttribute('id', b);
 c.setAttribute('src', a);
 }
return c; /* 返回创建成功的script标签元素 */
 };
测速数据提交与封装/**
 * 绑定 submitDataForPageSpeed 方法
 *
 * @param Object a Map对象
 */
 PageSpeed.submitDataForPageSpeed = function(a) {
 var b = {
 'name': '',
 'rate': 0
 };
 b.name = a.name;
 b.rate = a.rate;
/* 计算a.PAGE_SPEED_TIME数组最后一个元素与第一个元素的差值 */
 b['1'] = a.PAGE_SPEED_TIME[a.PAGE_SPEED_TIME.length - 1] - a.PAGE_SPEED_TIME[0];
for (var i = 1; i < a.PAGE_SPEED_TIME.length - 1; i++) {
 b[(i + 1) + ''] = a.PAGE_SPEED_TIME[i] - a.PAGE_SPEED_TIME[0]
 }
/* 提交速度测试结果的目标脚本地址 */
 var c = 'http://pagespeed-ied.qq.com/r.cgi';
/* 遍历b数组的元素,构建查询字符串 */
 var d = [];
 for (var p in b) {
 d.push(p + '=' + b[p])
 }
 c += '?' + d.join('&');
/* 创建script标签以提交测速结果 */
 PageSpeed.createScript(c, 'submitForPageSpeed')
 };
默认提交策略与随机概率控制/**
 * 绑定 defaultSubmit 方法
 *
 */
 PageSpeed.defaultSubmit = function() {
 var a = '';
 try {
 a = location.host
 } catch(e) {}
var b = {
 'name': a,
 'rate': 1,
 'PAGE_SPEED_TIME': []
 };
if (!b.name) {
 return
 }
if (! (typeof(PAGE_SPEED_TIME) == 'object' && PAGE_SPEED_TIME instanceof Array)) {
 return
 }
/* 获取新的时间戳 */
 PAGE_SPEED_TIME.push(new Date().getTime());
b.PAGE_SPEED_TIME = PAGE_SPEED_TIME;
/*
 * 此处代码逻辑存疑:为何需要引入新变量aaa,直接使用a似乎即可?
 * try ... catch结构中使用了新变量aaaa,但后续代码中从未使用,这是否为笔误?是否应为aaa?
 */
 var aaa = '';
 try {
 aaaa = location.host
 } catch(e) {}
var c = Math.floor(Math.random() * 10000);
if (aaa == "ktv.qq.com" || aaa == "ttd.qq.com" || aaa == "tian.qq.com" || aaa == "sura.qq.com" || aaa == "gw.tnt.qq.com" || aaa == "007.qq.com") {
 c = Math.floor(Math.random() * 1000);
 }
/* 根据随机概率提交数据 */
 if (c <= b.rate * 1) {
 PageSpeed.submitDataForPageSpeed(b);
 }
 };
/**
 * 绑定submit方法(可能用于CDN测速)
 *
 * @param String a 名称
 */
 PageSpeed.submit = function(a) {
 var b = PageSpeed.cdn_page_speed_submitData;
 var c = {};
 for (var p in b) {
 c[p] = b[p]
 }
 c.name = a || c.name;
 PageSpeed.submitDataForPageSpeed(c);
 }
})();
try {
 /* 延迟1秒后尝试提交数据 */
 setTimeout(function() {
 PageSpeed.defaultSubmit()
 },
 1000);
} catch(e) {}
/* 最后这段注释中的第二段为32位16进制数字,推测类似于ETag,用于标记内容版本 */
/* |xGv00|ca82276cd78ac911d3d4310ba1408236 */

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章