您的位置:首页 > Web前端 > JavaScript

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

2013-11-26 11:52 323 查看
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;

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: