本文是阅读《高性能JavaScript》一书后,从 Ajax 模块对JavaScript性能优化做了部分总结,记录一下。可能总结的不好,不是很完整,也希望各位大佬能多给出一些建议。万分感谢!
请求数据
有五种常用技术:
XMLHttpRequest(XHR)
Dynamic script tag insertion 动态脚本注入
iframes
Comet
Multipart XHR
XMLHttpRequest
目前最常用的技术,他允许异步发送和接收数据。所有的主流浏览器对它都提供了完善的支持,而且它还能精准的控制发送请求和数据接收。
范例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19var url = '/data.php';
var params = [
'id=934875',
'limit=20'
];
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if (req.readyState === 4) {
var responseHeaders = req.getAllResponseHeaders(); // 获取响应头信息
var data = req.responseText; // 获取数据
// 数据处理
}
}
req.open('GET', url + '?' + params.join('&'), true);
req.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); // 设置请求头信息
req.send(null);通过监听 readyState 值等于 3,可以与正在传输的服务器响应进行交互:
1
2
3
4
5
6
7
8
9req.onreadystatechange = function() {
if (req.readyState === 3) { // 接收到部分信息,但不是所有
var dataSoFar = req.responseText;
...
} else if (req.readyState === 4) { // 所有信息接收完毕
...
}
}
动态脚本注入
这种技术克服了 XHR 的最大限制:它能跨域请求数据。范例:
1
2
3
4
5
6
7
8
9
10
11var scriptElement = document.createElement('script');
scriptElement.src = 'http://any-domin.com/javascript/lib.js';
document.getElementByTagName('head')[0].appendChild(scriptElement);
function jsonCallback(jsonString) {
var data = eval('(' + jsonString + ')');
// 处理数据...
}
// 本例中 libs 文件需要将数据封装在 jsonCallback 函数里:
// jsonCallback({ "status": 1, "colors": ['#fff', '#000', '#ff0000']});
- 弊端:
1. 不能设置请求的头信息
2. 参数传递只能使用 GET 请求
3. 不能设置请求的超时处理或重试
4. 不能使用纯 XML、JSON、或其他任何格式的数据,无论哪种格式,都必须封装在一个回调函数中
Multipart XHR
编写健壮的 MXHR 代码很复杂,但值得深入研究,访问以下网址可获取完整的类库:http://techfoolery.com/mxhr/。
优点:发送多个资源(图片,文件,HTML 片段)只用一次 HTTP 请求
适用场景:
- 页面包含了大量其他地方用不到的资源(因此也无须缓存),尤其是图片
- 网站已经在每个页面中使用一个独立打包的 JavaScript 或 CSS 文件以减少 HTTP请求
局限性:
- 这种方式获得的资源不能被缓存
- 老版的 IE 不支持 readyState 为 3 的状态和 data: URL。因此无法使用
发送数据
XMLHttpRequest
当使用XHR 发送数据到服务器时, GET方式会更快。这是因为,对于少量数据而言,一个 GET 请求网服务器只发送一个数据包。而一个 POST 请求,至少要发送两个数据包,一个装载头信息,另一个装在 POST 正文。 POST 更适合发送大量数据到服务器,因为它不关心额外数据包的数量,另一个原因是 IE 对URL 长度有限制,它不可能使用过长的 GET 请求
Beacons(信标)
这项技术非常类似动态脚本注入。使用JavaScript 创建一个新的 Image 对象,并把 src 属性设置为服务器上脚本的 URL。该 URL 包含了我们要通过 GET 传回的键值对数据。
请注意,并没有创建 img 元素或把它插入 DOM
1 | var url = '/status_tracker.php'; |
信标是向服务器会窜数据中最快切最有想的方式。服务器根本不需要发送人性和响应文本,因此你也无须担心客户端下载数据。唯一缺点是你接收到的响应类型是有限的。如果你需要返回大量数据,请使用XHR。
数据格式
不同数据格式情况下,响应内容大小和解析事件
格式 | 大小 | 下载耗时 | 解析耗时 | 总耗时 |
---|---|---|---|---|
标准的 XML | 582 960 字节 | 999.4 毫秒 | 343.1 毫秒 | 1342.5 毫秒 |
简化的 XML | 437 960 字节 | 475.1 毫秒 | 83.1 毫秒 | 558.2 毫秒 |
标准 JSON | 487 895 字节 | 527.7 毫秒 | 26.7 毫秒 | 554.4 毫秒 |
简化的 JSON | 392 895 字节 | 498.7 毫秒 | 29.0 毫秒 | 527.7 毫秒 |
数组 JSON | 292 895 字节 | 305.4 毫秒 | 18.6 毫秒 | 324.0 毫秒 |
Verbose JSON-P | 487 913 字节 | 598.2 毫秒 | 0.0 毫秒 | 598.2 毫秒 |
Simple JSON-P | 392 913 字节 | 454.0 毫秒 | 3.1 毫秒 | 457.1 毫秒 |
Array JSON-P | 292 912 字节 | 316.0 毫秒 | 3.4 毫秒 | 319.4 毫秒 |
HTML | 1063 416 字节 | 273.1 毫秒 | 121.4 毫秒 | 394.5 毫秒 |
Custom Format (XHR) | 222 892 字节 | 63.1 毫秒 | 14.5 毫秒 | 77.6 毫秒 |
Custom Format (script insertion) | 222 912 字节 | 66.3 毫秒 | 11.7 毫秒 | 78.0 毫秒 |
JSON 是高性能 Ajax 的基础,尤其在使用动态脚本注入时。
数据格式总结
通常来说数据格式越轻量级越好,JSON 和字符分隔的自定义格式是最好的。如果数据集很大并且对解析事件有要求,那么就从如下两种格式中作出选择:
JSON-P 格式,使用动态脚本注入获取。它把数据当做可执行 JavaScript 而不是字符串,解析速度极快。它能跨域使用,但涉及敏感数据时不应该使用它
字符分隔的自定义格式,使用XHR 或动态脚本注入获取,用 split() 解析。这项技术解析大数据比 JSON-P略快,而且通常文件尺寸更小
Ajax 性能指南
缓存数据
设置 HTTP 头信息
如果希望 Ajax 响应能够被浏览器缓存,那么你必须使用 GET 方式发出请求。但这还不够,你还必须在响应中发送正确的 HTTP 头信息。Expires 头信息会告诉浏览器应该缓存响应多久。
设置 Expires 头信息是确保浏览器缓存 Ajax 响应最简单的方法。
本地数据存储
直接将服务器接收到的数据存储到一个对象中,以 URL 为键值对作为索引。使用时直接从对象中获取。清除缓存时删除对应的 URL 属性即可
Ajax 类库的局限性
- 不能放到到 XMLHttpRequest 的完整功能
直接操作 XHR 对象减少了函数开销,进一步提升了性能。需要的是,如果放弃使用 Ajax 类库,那么你可能在一些古怪的浏览器上遇到一些问题。
小结
作为数据格式,纯文本和 HTML 是高度限制的,但它们可节省客户端的 CPU 周期。XML 被广泛应用普遍支持,但它非常冗长且解析缓慢。JSON 是轻量级的,解析迅速(作为本地代码而不是字符串),交互性与 XML 相当。字符分隔的自定义格式非常轻量,在大量数据集解析时速度最快,但需要编写额外的程序在服务器端构造格式,并在客户端解析。
当从页面域请求数据时,XHR 提供最完善的控制和灵活性,尽管它将所有传入数据视为一个字符串,这有可能降低解析速度。另一方面,动态脚本标签插入技术允许跨域请求和本地运行 JavaScript 和 JSON,虽然它的接口不够安全,而且不能读取信息头或响应报文代码。多部分 XHR 可减少请求的数量,可在一次响应中处理不同的文件类型,尽管它不能缓存收到的响应报文。当发送数据时,图像灯标是最简单和最有效的方法。XHR 也可用 POST 方法发送大量数据。
除这些格式和传输技术之外,还有一些准则有助于进一步提高 Ajax 的速度:
减少请求数量,可通过 JavaScript 和 CSS 文件打包,或者使用 MXHR
缩短页面的加载时间,在页面其它内容加载之后,使用 Ajax 获取少量重要文件
确保代码错误不要直接显示给用户,并在服务器端处理错误
知道何时使用成熟的 Ajax 类库,以及何时编写自己的底层 Ajax 代码