没有XHR,Ajax精彩依旧
2010-10-19 00:00 Feather 阅读(590) 评论(0) 收藏 举报这是我在上周工作室技术交流的时候演讲的主题。ppt很简略,在这边详细介绍一下。
由于是面对工作室全部成员,ppt前面用了5页介绍什么是Ajax,什么是XHR,在这里就尽量免了,我们直奔主题吧。
真实的Ajax
如果有人问您什么是Ajax,您会怎么回答?说Asynchronous JavaScript and XML?还是粗略地说“一系列客户端和服务器交互的技术”?我们都认为自己知道什么是Ajax,却又很难完整说出什么是Ajax,Ajax包括什么技术。事实上,或许我们真的不是很清楚。
我们登录淘宝时候,点击登录按钮,按钮立刻显示“登陆中”,并且按钮变成不可用,防止网络延迟时用户重复提交表单。
这是Ajax么?这个例子中我们很清楚里面的实现,它没有对服务器进行异步交互,但它确实是Ajax技术的一部分。
因为根据Ajax提出者Jesse James Garrett建议,Ajax技术包括:
1.基于web标准XHTML+CSS的表示;
2.使用 DOM进行动态显示及交互;
3.使用 XML 和 XSLT 进行数据交换及相关操作;
4.使用 XMLHttpRequest 进行异步数据查询、检索;
在我们传统观念中,Ajax主要任务是通过XHR与服务器异步交互,然后解析呈现。
如果说Ajax精彩,那它的精彩之处应该就是在于两个地方,一是异步下载,二是实时呈现。也就是Jesse James Garret说到的这四类技术。
我们为什么要纠缠这些概念呢?因为我在想这篇文章题目的时候思索了很久,因为我当时认为我介绍的不是Ajax,所以曾经想用“类Ajax”,“泛Ajax”来做主题,后来纠缠清这些概念之后,发现一切皆Ajax,于是有了这个标题。
实时渲染
实时渲染其实跟动态显示是都一个差不多的概念,也算是DHTML引入的一个概念。我们用js对网页文档的修改户会动态地实时地呈现出来。这是Ajax技术中必不可少的一部分,因为是它实现了人机交互,具体讲是用户和客户端交互,而XHR是客户端和服务器交互。
我之所以这是说“实时渲染”特性而不是很多文章里说的“动态显示”,因为我觉得,“显示”两个字会给人误导。这种特性不仅可以实现动态显示,动态消失,也可以实现动态下载。其实这就是我们这里要谈论的主题。
当我们我们往文档插入<div><h1> <table>这些一般标签时,浏览器会实时解析,呈现;
当我们插入<img> <link> <script> <iframe>这些带有资源引用的标签的时候,浏览器会实时解析,下载,呈现。
<img>标签
我们先讲一个例子,很多表单都要求输入验证码,在我之前负责的新生网文章的评论也是需要输入验证码的,但是一张验证图片带来的开销也是不少的:绘画图片:消耗CPU;存储正确的验证码:消耗内存;下载图片:占用带宽,增加http连接,减低响应。而实际上网站的每篇文章评论率不到1%,如果每次页面打开都自动下载这张图片的话,会在一定程度上浪费服务器资源。
像很多网站一样,这里我们采用了当验证码输入框获得焦点的时候才下载这篇文章。下面是一份简化版的Demo:
<input type="button" value="加载" onclick="clickhandler()" />
<div id="box"> </div>
<script type="text/javascript">
function clickhandler(){
document.getElementById('box').innerHTML='<img src="029084058.jpg">‘
}
</script>
点击按钮之后,div里面会被注入一段img标签,浏览器会随之解析下载渲染。
一般待注入的标签会存放在textarea,pre,js变量,html注释中,以防被浏览器下载文档的时候解析。
这种技术还有在预加载(Pre-Loading)和延迟加载(Lazy-Loading)的时候用到,下面也会一一讲到。
预加载(PreLoading)
预加载的应用比较少,我觉得它在某些应用上可以发挥很大的好处,例如说吧:图片展播,当用户打开一辑图片中的一张的时候,他很有可能会继续看第二张第三张,如果我们要在用户点击的时候才加载,那么很可能需要用户等待一段时间下载图片,体验很差。这时预加载就比较有用了。
优化的办法是:在用户点击下一张前,js预先下载这张图片。预加载方法也很多:
1.Dom操作(节点,innerHTML注入,修改属性...),这种办法就是用实时渲染特性来实现下载,为了让图片不立刻显示,可以display:none一下。
2.BOM,建立一个image对象,然后对其src属性赋值,图片就会下载。等到需要显示的时候,用Dom操作插入img标签,由于图片已经下载,浏览器会从缓存中读取图片。
3.XHR,XHR不仅可以下载文本,也可以下载图片,下载后操作跟上面一样。
延迟下载(Lazy-Loading)
延迟下载也叫“懒惰下载”,或者“按需下载”,是目前比较流行的一种技术,淘宝,京东,拍拍等很多网站都应用了这个技术。
其大概原理是:
- 把网页所有需要延迟下载的图片的真实地址放在一个自定义属性中,例如(_src),而真正的src 就引用一张空白图片作为占位符。
- 对页面滚动进行监听,通过取得元素高度,页面长度,滚动高度等等属性检查图片是否在或者准备在用户的可视范围内,如果是,则把_src属性赋给src,下载图片。
这种技术最大好处是减少http响应,加快响应,节省带宽。
现在有很多框架都带有这些功能的实现,例如Juery的delay,kissy的DataLazyload。
除了延迟下载图片,延迟下载其他资源的应用例子也很多,例如广泛在微博实现的延迟下载数据。
<link>标签
和img标签一样,插入link标签或者修改其href属性,浏览器会实时下载并且应用该样式表。
这个其实应用不多,比较常见的大概就是用它来实现换肤功能,我们用一个小小的Demo带过吧。
<link href="a.css" type="text/css" rel="stylesheet" id="css" />
<input type="button" value="换肤" onclick="clickhandler()" />
<script type="text/javascript">
function clickhandler(){
document.getElementById('css').href="b.css"
}
</script>
点击按钮后,页面上应用了a样式表的样式会被撤销,然后b样式表会被下载并且应用。
<script>标签
通过实时渲染来下载脚本是一系列很奇妙并且很复杂的技术。因为,本身脚本下载就有很多学问。
脚本下载和其他资源下载不一样,在传统浏览器中,脚本不会并行下载,并且会阻塞渲染,阻塞其他资源下载,而其他资源标签不会。
有人可能理解不了为什么会这样,这是关乎到执行顺序的问题,这里举一个简单的例子,如果我们在前面引入一个Jquery,在接着代码块中就使用了Jquery的方法,但是这时候Juqery还没有下载完。未免解析出错,浏览器就把其他工作都放下,等到脚本下载完再继续。
在某些现代浏览器中,它们可以实现并行下载,并且保持执行顺序,但是在不同浏览器中还是有不同程度的阻塞。
使用插入<script>标签可以在一定程度上解决这些问题。
譬如:1.创建Script DOM并插入文档可以实现:并行下载,无阻塞;2.用Document.write()写入标签可以在IE中并行下载。
类似的方法不少,在《高性能网站建设进阶指南》中有详细介绍,推荐一读。
<iframe>标签
这个标签应用比较多,而且五花八门。例如,上传控件,弹出框,我早期也尝试通过隐藏的iframe来实现Ajax的历史记录产生,也试过用来模拟多线程(失败告终)。
接着,我还是用一个小Demo带过最后一Part吧。
Demo:用iframe模拟Jquey的Ajax方法:
function ajax(url,callback)
{
var iframe=document.createElement("iframe");
iframe.src=url;
iframe.id="AjaxByIframe";
iframe.style.display='none';//隐藏iframe
iframe.onload=function(){//加载后调用callback
var content=iframe.contentWindow.document.getElementsByTagName("html")[0];
callback(content.innerText||content.textContent);//兼容FF
document.body.removeChild(iframe);//移除iframe
}
document.getElementsByTagName("body")[0].appendChild(iframe)
}
浙公网安备 33010602011771号