javascript 性能分析:Ajax 异步javascript和xml

ajax 是高性能javascript的基石 可以通过延迟下载大量资源是页面加载更快 通过客户端和服务端异步传送数据 避免页面集体加载 局部刷新页面 通过选择正确的传输技术和最有效的数据格式 可以改善和用户的体验。

一 数据传输

五种常用技术向服务器请求数据:

XMLHttpRequest

Dynamic script tag insertion 动态脚本标签插入

iframes

Comet

Multipart XHR

 

XMLHttpRequest XHR :

 

var url = '/data.php';
var params = [
'id=934875',
'limit=20'
];
var req = new XMLHttpRequest();
req.onreadystatechange = function() {

if (req.readyState === 4) {
var responseHeaders = req.getAllResponseHeaders(); // Get the response headers.
var data = req.responseText; // Get the data.
// Process the data here...
}
}
req.open('GET', url + '?' + params.join('&'), true);
req.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); // Set a request header.
req.send(null); // Send the request.

其中 req.readyState === 3 表示正在和服务器交互 响应报文 还在传输中 所谓的流 但是老版本的浏览器不支持流

缺点是处理大数据比较慢

使用get还是post方式:

 如果只是请求不改变服务器的状态只是取回数据(幂等动作)使用get get请求被缓冲起来 如果是多次提取相同的数据可提高性能 但当Url和参数的长度超过2048个字符最好使用post IE限制Url长度 过长会被截短

动态脚本标签插入:

克服了xhr的最大限制 可以从不同域的服务器上获取数据。

var scriptElement = document.createElement('script');
scriptElement.src = 'http://any-domain.com/javascript/lib.js';
document.getElementsByTagName_r('head')[0].appendChild(scriptElement);

不能通过请求发送信息头 参数只能是get方式不能post 不能设置请求超时和重试 不知道是否失败 必须等数据返回之后才可以访问。

var scriptElement = document.createElement('script');
scriptElement.src = 'http://any-domain.com/javascript/lib.js';
document.getElementsByTagName_r('head')[0].appendChild(scriptElement);

function jsonCallback(jsonString) {
var data = ('(' + jsonString + ')');
// Process the data here...
}

多部分 XHR  (MXHR):允许一个http请求获取服务器多个资源。

简单的例子:

var req = new XMLHttpRequest();
req.open('GET', 'rollup_images.php', true);
req.onreadystatechange = function() {
if (req.readyState == 4) {
splitImages(req.responseText);
}
};
req.send(null);

---------------------------------------

简单的图片处理

$images = array('kitten.jpg', 'sunset.jpg', 'baby.jpg');
foreach ($images as $image) {
$image_fh = fopen($image, 'r');
$image_data = fread($image_fh, filesize($image));
fclose($image_fh);
$payloads[] = base64_encode($image_data);
}
// Roll up those strings into one long string and output it.
$newline = chr(1); // This character won't appear naturally in any base64 string.
echo implode($newline, $payloads);

function splitImages(imageString) {
var imageData = imageString.split("\u0001");
var imageElement;
for (var i = 0, len = imageData.length; i < len; i++) {
imageElement = document.createElement('img');
imageElement.src = 'data:image/jpeg;base64,' + imageData[i];
document.getElementById('container').appendChild(imageElement);

}
}

javascript代码和css样式的处理:

function handleImageData(data, mimeType) {
var img = document.createElement('img');
img.src = 'data:' + mimeType + ';base64,' + data;
return img;
}
function handleCss(data) {
var style = document.createElement('style');
style.type = 'text/css';
var node = document.createTextNode(data);

style.appendChild(node);
document.getElementsByTagName_r('head')[0].appendChild(style);
}
function handleJavaScript(data) {
(data);
}

使用MXHR响应报文越来越大 有必要在每个资源收到时立即处理 而不是等待整个响应报文接收完成处理:可以使用readyState 3监听

var req = new XMLHttpRequest();
var getLatestPacketInterval, lastLength = 0;
req.open('GET', 'rollup_images.php', true);
req.onreadystatechange = readyStateHandler;
req.send(null);
function readyStateHandler{
if (req.readyState === 3 && getLatestPacketInterval === null) {
// Start polling.
getLatestPacketInterval = window.setInterval(function() {
getLatestPacket();
}, 15);
}
if (req.readyState === 4) {

// Stop polling.
clearInterval(getLatestPacketInterval);
// Get the last packet.
getLatestPacket();
}

}
function getLatestPacket() {
var length = req.responseText.length;
var packet = req.responseText.substring(lastLength, length);
processPacket(packet);
lastLength = length;
}

缺点不支持缓存。

网页包含许多其他地方不会用到的资源(所以不需要缓存) 尤其是图片  可以减少javascript和css文件http请求。

post方式重试:

function xhrPost(url, params, callback) {
var req = new XMLHttpRequest();
req.onerror = function() {
setTimeout(function() {
xhrPost(url, params, callback);
}, 1000);
};
req.onreadystatechange = function() {
if (req.readyState == 4) {
if (callback && typeof callback === 'function') {
callback();
}
}
};

req.open('POST', url, true);
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
req.setRequestHeader('Content-Length', params.length);

req.send(params.join('&'));
}

Beacons 灯标

传送数据格式:

XML:必须提前知道详细结构 如何拼装成javascript对象

例子:

<?xml version="1.0" encoding='UTF-8'?>
<users total="4">
<user id="1">

<username>alice</username>
<realname>Alice Smith</realname>
<email>alice@alicesmith.com</email>
</user>
<user id="2">
<username>bob</username>
<realname>Bob Jones</realname>
<email>bob@bobjones.com</email>
</user>
<user id="3">
<username>carol</username>
<realname>Carol Williams</realname>
<email>carol@carolwilliams.com</email>
</user>
<user id="4">

<username>dave</username>
<realname>Dave Johnson</realname>
<email>dave@davejohnson.com</email>
</user>
</users>

解析:

function parseXML(responseXML) {
var users = [];
var userNodes = responseXML.getElementsByTagName_r('users');
var node, usernameNodes, usernameNode, username,
realnameNodes, realnameNode, realname,
emailNodes, emailNode, email;
for (var i = 0, len = userNodes.length; i < len; i++) {
node = userNodes[i];
username = realname = email = '';
usernameNodes = node.getElementsByTagName_r('username');
if (usernameNodes && usernameNodes[0]) {
usernameNode = usernameNodes[0];
username = (usernameNodes.firstChild) ?
usernameNodes.firstChild.nodeValue : '';
}

realnameNodes = node.getElementsByTagName_r('realname');

if (realnameNodes && realnameNodes[0]) {
realnameNode = realnameNodes[0];
realname = (realnameNodes.firstChild) ?
realnameNodes.firstChild.nodeValue : '';
}
emailNodes = node.getElementsByTagName_r('email');
if (emailNodes && emailNodes[0]) {
emailNode = emailNodes[0];
email = (emailNodes.firstChild) ?
emailNodes.firstChild.nodeValue : '';
}
users[i] = {
id: node.getAttribute('id'),
username: username,
realname: realname,
email: email
};

}
return users;
}

更有效的方式将每个值存储为user标签的属性 这样文件尺寸更小

<?xml version="1.0" encoding='UTF-8'?>
<users total="4">
<user id="1-id001" username="alice" realname="Alice Smith" email="
alice@alicesmith.com" />
<user id="2-id001" username="bob" realname="Bob Jones" email="
bob@bobjones.com" />
<user id="3-id001" username="carol" realname="Carol Williams" email="
carol@carolwilliams.com" />
<user id="4-id001" username="dave" realname="Dave Johnson" email="
dave@davejohnson.com" />
</users>

解析:

function parseXML(responseXML) {
var users = [];
var userNodes = responseXML.getElementsByTagName_r('users');
for (var i = 0, len = userNodes.length; i < len; i++) {
users[i] = {
id: userNodes[i].getAttribute('id'),
username: userNodes[i].getAttribute('username'),
realname: userNodes[i].getAttribute('realname'),
email: userNodes[i].getAttribute('email')
};
}
return users;
}

XPath 数据格式:在分析xml文档时比getElementsByTagName快得多 但是没有得到广泛支持 必须使用老式的DOM遍历写代码

JSON 数据格式:轻量级并易于解析的数据格式 它是按照javascript对象和数组字面语法所编写的

[
{"id":1, "username":"alice", "realname": "Alice Smith", "email":"
alice@alicesmith.com"},
{"id":2, "username":"bob", "realname": "Bob Jones", "email":"
bob@bobjones.com"},
{"id":3, "username":"carol", "realname": "Carol Williams","email":"
carol@carolwilliams.com"},
{"id":4, "username":"dave", "realname": "Dave Johnson", "email":"
dave@davejohnson.com"}
]

function parseJSON(responseText) {
return ('(' + responseText + ')');
}

改造更简单的版本:

[
{ "i": 1, "u": "alice", "r": "Alice Smith", "e": "
alice@alicesmith.com" },
{ "i": 2, "u": "bob", "r": "Bob Jones", "e": "
bob@bobjones.com" },
{ "i": 3, "u": "carol", "r": "Carol Williams", "e": "
carol@carolwilliams.com" },
{ "i": 4, "u": "dave", "r": "Dave Johnson", "e": "
dave@davejohnson.com" }
]

解析:

function parseJSON(responseText) {
var users = [];
var usersArray = ('(' + responseText + ')');
for (var i = 0, len = usersArray.length; i < len; i++) {
users[i] = {
id: usersArray[i][0],
username: usersArray[i][1],
realname: usersArray[i][2],
email: usersArray[i][3]
};
}
return users;
}

三中json格式的性能:Array JSON》Simple JSON 》Verbose JSON

JSON-P 数据格式:

当使用动态脚本标签插入时 JSON数据被视为另一个javascript文件并作为本地代码执行 为做到这一点 数据必须被包装在回调函数中 这就是所谓的 JSon填充 json_p

能够跨域使用

parseJSON([
{"id":1, "username":"alice", "realname":"Alice Smith", "email":"
alice@alicesmith.com"},
{"id":2, "username":"bob", "realname":"Bob Jones", "email":"
bob@bobjones.com"},
{"id":3, "username":"carol", "realname":"Carol Williams", "email":"
carol@carolwilliams.com"},
{"id":4, "username":"dave", "realname":"Dave Johnson", "email":"
dave@davejohnson.com"}
]);

HTML数据格式:

document.getElementById('data-container').innerHTML = req.responseText;

自定义格式:

多维数组格式split()分割解析

function parseCustomFormat(responseText) {
var users = [];
var usersEncoded = responseText.split(';');
var userArray;
for (var i = 0, len = usersEncoded.length; i < len; i++) {
userArray = usersEncoded[i].split(':');
users[i] = {
id: userArray[0],
username: userArray[1],
realname: userArray[2],
email: userArray[3]
};
}
return users;
}

手动缓存:

var localCache = {};
function xhrRequest(url, callback) {
// Check the local cache for this URL.
if (localCache[url]) {
callback.success(localCache[url]);
return;
}
// If this URL wasn't found in the cache, make the request.
var req = createXhrObject();
req.onerror = function() {
callback.error();
};
req.onreadystatechange = function() {
if (req.readyState == 4) {
if (req.responseText === '' || req.status == '404') {
callback.error();
return;
}
// Store the response on the local cache.
localCache[url] = req.responseText;
callback.success(req.responseText);

}
};
req.open("GET", url, true);
req.send(null);
}

了解 ajax 的限制:

如果要用到流功能必须监听readyState 3 在一个大的响应报文没有完全接收之前就开始解析它 这样就可以实时处理报文片段 这也就是MXhr提高性能的原因 但是大多数javascript库不允许你访问readystatechange事件。

function createXhrObject() {
var msxml_progid = [
'MSXML2.XMLHTTP.6.0',

MSXML3.XMLHTTP',
'Microsoft.XMLHTTP', // Doesn't support readyState 3.
'MSXML2.XMLHTTP.3.0', // Doesn't support readyState 3.
];
var req;
try {
req = new XMLHttpRequest(); // Try the standard way first.
}
catch(e) {
for (var i = 0, len = msxml_progid.length; i < len; ++i) {
try {
req = new ActiveXObject(msxml_progid[i]);
break;
}
catch(e2) { }
}
}
finally {
return req;
}
}

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值