【简介】Ajax 是高性能 JavaScript 的基础。它可以通过延迟下载体积较大的资源文件来使得页面加载速度更快。它通过异步的方式在客户端和服务端之间传输数据,从而避免了页面资源一窝蜂地下载。它甚至可以只用一个 HTTP 请求就获取整个完整的页面资源。选择适合的传输方式和最有效的数据格式,可以显著改善用户和网站的交互体验。
2. 发送数据(Sending Data)
有时候你并不关心接收数据,而只需要将数据发送到服务器。当数据只需要发送到服务器时,有两种广泛使用的技术:XHR 和信标(beacons),这里我们只讲 XHR。
2-1 XHR(XMLHttpRequest)
<script type="text/javascript">
var url = '/data.php';
var params = ['id=242', 'limit=20'];
var req = new XMLHttpRequest();
req.onerror = function() {
// 出错
}
req.onreadystatechange = function() {
if (req.readyState == 4) {
// 成功
}
}
req.open('POST', url, true);
req.setRequestHeader('Content-Type', 'application/x-www-from-urlencoded');
req.setRequestHeader('Content-Length', params.length);
req.send(params.join('&'));
</script>
对于发送到服务器的是至关重要的数据,可以增加一些代码来实现在失败时重试:
</script>
<script type="text/javascript">
function xhrPost(url, params, callback) {
var req = new XMLHttpRequest();
req.onerror = function() {
// 失败时,添加一个定时器,1 秒后重试
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-from-urlencoded');
req.setRequestHeader('Content-Length', params.length);
req.send(params.join('&'));
}
</script>
3. 数据格式
当考虑数据传输技术时,需要考虑:功能集、兼容性、性能以及方向(发送给服务器还是从服务器接收)。而当考虑数据格式时,唯一的标准就是速度。
没有哪一种数据格式会始终比其他格式更好,优劣取决于要传输的数据以及它在页面上的用途,一种可能下载更快,而另一种可能解析更快。
3-1. XML
XML 是 Ajax 早期时候使用最多的数据格式。当时它有很多的优势:极佳的通用性(服务端和客户端都能完美支持)、格式严格,易于验证。那时 JSON 还没有正式作为交换格式,几乎所有服务端语言都有操作 XML 的类库。
我们来看这样一段 XML :
<?xml version='1.0' encoding='utf-8' ?>
<users total='3'>
<user id='1'>
<username>abc1</username>
<userage>23</userage>
</user>
<user id='2'>
<username>abc2</username>
<userage>24</userage>
</user>
<user id='3'>
<username>abc3</username>
<userage>21</userage>
</user>
</users>
相比其他格式,XML 及其冗长。每个单独的数据片段都依赖大量的结构。而且解析 XML 需要占用 JavaScript 程序员相当一部分的精力。除了要提前知道纤细结构之外,还必须确切的知道如何解析这个结构并费力地将它重组到 JavaScript 对象中。
下面我们来演示解析上面这段 XML 的过程:
function parseXML(responseXML) {
var users = [];
var userNodes = document.getElementsByTagName('user');
var userNode, usernameNode, username, userageNode, userage;
for (var i = 0, len=userNodes.length; i < len; i++) {
userNode = userNodes[i];
usernameNode = userNode.getElementsByTagName('name')[0];
username = (usernameNode.firstChild) ? usernameNode.firstChild.nodeValue : '';
userageNode = userNode.getElementsByTagName('age')[0];
userage = (userageNode.firstChild) ? userageNode.firstChild.nodeValue : '';
users[i] = {
id:userNode.getAttribute('id'),
username: username,
userage:userage
};
}
return users;
}
一个更有效的方法来处理读取值,将 username、userage 都作为 user 标签的属性,这样会更容易读取。
<?xml version='1.0' encoding='utf-8' ?>
<users total='3'>
<user id='1' username="abc1" userage="23" />
<user id='2' username="abc2" userage="24" />
<user id='3' username="abc3" userage="21" />
</users>
这样子的封装,在 JavaScript 中更容易处理:
<script type="text/javascript">
function parseXML(responseXML) {
var users = [];
var userNodes = document.getElementsByTagName('user');
for (var i = 0, len=userNodes.length; i < len; i++) {
users[i] = {
id:userNodes[i].getAttribute('id'),
username:userNodes[i].getAttribute('username'),
userage:userNodes[i].getAttribute('userage')
};
}
return users;
}
</script>
这样的方式,虽然更容易使用 JavaScript 读取数据,但是其数据的结构性不如第一种来的更加层次分明。
3-2. JSON
JSON 是一种使用 JavaScript 对象和数组直接编写的轻量级且易于解析的数据格式:
[
{"id":1, "username":"abc1", "userage":23},
{"id":2, "username":"abc2", "userage":24},
{"id":3, "username":"abc3", "userage":21}
]
将用户表示为一个对象,用户列表表示为一个数组。这意味着当它被求值或封装在一个回调函数中时,JSON 数据就是一段可执行的 JavaScript 代码,不需要像 XML 那样通过转换,就能 JavaScript 非常方便的调用。
正如 XML 那样,它可以提炼一个更为简化的版本。这种情况下,我们可以把属性名缩短(相对的可读性会变差):
[
{"i":1, "u":"abc1", "a":23},
{"i":2, "u":"abc2", "a":24},
{"i":3, "u":"abc3", "a":21}
]
它将相同的数据以更少的结构和更小的文件大小传送给浏览器。更进一步,我们可以去掉属性名,与其他两种格式相比,这种格式可读性更差,也更脆弱,但文件尺寸却小得多,大约只有标准 JSON 的一半。
[
[ 1, "abc1", 23 ],
[ 2, "abc2", 24 ],
[ 3, "abc3", 21 ]
]
虽然可读性差,但只要保持数据的顺序,也能很方便的解析:
function parseJSON(responseArr) {
var users = [];
for (var i = 0, len = responseArr.length; i < len; i++) {
users[i] = {
id: responseArr[i][0],
username: responseArr[i][1],
userage: responseArr[i][2]
};
}
return users;
}
3-3. HTML
如果请求的数据需要被转成 HTML 以显示到页面上,可以在服务器上完成数据封装,这样会比在 JavaScript 中更快。即在服务器上构件号整个 HTML 再传回客户端,JavaScript 可以很方便地通过 innerHTML 属性把它插入到页面中。
比如我们直接在服务器上构建好这样一个 HTML 片段即可:
<ul class="uses">
<li class="user" id="1">
<span class="username">姓名:abc1</span>
<span class="userage">年龄:23</span>
</li>
<li class="user" id="2">
<span class="username">姓名:abc2</span>
<span class="userage">年龄:24</span>
</li>
<li class="user" id="3">
<span class="username">姓名:abc3</span>
<span class="userage">年龄:21</span>
</li>
</ul>
这种技术的问题是 HTML 是一种臃肿的数据格式,甚至比 XML 更繁杂。作为一种数据格式,它既缓慢,又臃肿。
3-4. 小结
作为数据格式,纯文本和 HTML 只适用于特定场合,但他们可以节省客户端的 CPU 周期;XML 被广泛应用而且支持良好,但是它十分笨重且解析缓慢;JSON 是一种轻量级的,解析速度快,通用性和 XML 相当的数据格式。
附: 欢迎大家关注我的新浪微博 - 一点编程,了解最新动态 。