ajax大家都很熟悉了,我们知道ajax会有一些弊端,H5出来了两个新的API叫做pushState和replaceState,这两个可以很好的解决ajax不能历史返回的问题。先推荐一个博客,推荐的原因是要知其所以然,知道历史才能够更好的理解。下面是我的整理,由于是自己的整理,所以很多无关这两个API的,可以直接忽略,跳过直接看后面重点部分和demo。。
前言-ajax与传统web应用的比较
简单来说:
第一:是局部刷新,传统web应用要请求并重新读取一个整个页面。
第二:仅仅向服务器发送并取回必要的数据,不会像传统的web应用一样浪费很多带宽。
第三:减少了数据交换,减少了响应时间,响应的更快。
用户体验好,用户体验好,用户体验好
传统的Web应用交互由用户触发一个HTTP请求到服务器,服务器对其进行处理后再返回一个新的HTHL页到客户端, 每当服务器处理客户端提交的请求时,客户都只能空闲等待,并且哪怕只是一次很小的交互、只需从服务器端得到很简单的一个数据,都要返回一个完整的HTML页,而用户每次都要浪费时间和带宽去重新读取整个页面。这个做法浪费了许多带宽,由于每次应用的交互都需要向服务器发送请求,应用的响应时间就依赖于服务器的响应时间。这导致了用户界面的响应比本地应用慢得多。
与此不同,AJAX应用可以仅向服务器发送并取回必需的数据,它使用SOAP或其它一些基于XML的Web Service接口,并在客户端采用JavaScript处理来自服务器的响应。因为在服务器和浏览器之间交换的数据大量减少,结果我们就能看到响应更快的应用。同时很多的处理工作可以在发出请求的客户端机器上完成,所以Web服务器的处理时间也减少了。
ajax的工作原理
Ajax的工作原理相当于在用户和服务器之间加了—个中间层(AJAX引擎),使用户操作与服务器响应异步化。并不是所有的用户请求都提交给服务器,像—些数据验证和数据处理等都交给Ajax引擎自己来做, 只有确定需要从服务器读取新数据时再由Ajax引擎代为向服务器提交请求。
其实Ajax主要就是通过XMLHttpRequest对象来向服务器发送异步请求,然后从服务器端获得相应的数据,利用相应的数据来局部更新相应的页面。
ajax的缺点和优点
咱们先讲优点:
- 无刷新更新数据避免修改了那些不需要改变的信息,从而减少等待时间,用户体验很好。
- 异步通信中途不会阻止用户操作,具有更加迅速的响应能力。优化了b/s的沟通。
- 前后端负载均衡,后面的ajax的工作原理会讲到,ajax可以吧以前必须要服务器承担的工作留给客户端。利用客户端闲置的能力来处理,减轻服务器和带宽的负担,节约空间和宽带租用成本。并且减轻服务器的负担,ajax的原则是“按需取数据”,可以最大程度的减少冗余请求,和响应对服务器造成的负担。
- 基于标准,被支持
- 数据与呈现分离有利于分工合作。减少非技术人员对web应用程序错误。
再来看看缺点:
- ajax破坏了浏览器本身的机制,不能够有back和history的功能。
- ajax的安全问题,这使得开发者在不经意间会暴露更多的数据和服务器逻辑。ajax也难以避免一些一直的安全弱点,sql注入,xss等等。
- 破坏程序的异常处理机制(这一点在怎么理解?)
- 违背URL和资源定位的初衷,例如,我给你一个URL地址,如果采用了Ajax技术,也许你在该URL地址下面看到的和我在这个URL地址下看到的内容是不同的。这个和资源定位的初衷是相背离的。
- 对搜索引擎支持较弱。对搜索引擎的支持比较弱。如果使用不当,AJAX会增大网络数据的流量,从而降低整个系统的性能。
- 还有不容易调试那些问题。
重点:怎么解决不能有back和history这一问题?
先来看看history对象:
1 | window.history.back(); |
H5引入了history.pushState()
,history.replaceState()
这两个API,他们允许添加和修改history实体。需要和window.onpopstate
事件一起工作。这两个方法用来修改referrer,可以被用在修改状态后而为XMLHttpRequest对象创建的http header中。
pushState就是向history添加当前页面的记录,replaceState的参数和用法和pushState相同,区别在于replaceState是用于修改当前页面在history中的记录。这个我们后面也会在例子中用到。
其实pushState就是一个往堆栈添加一条历史记录。可以形象的理解成push。
pushState(data,title,[,url])
:data为一个对象或者为null,它会在触发window的popstate事件时,作为参数的state属性传递过去,title为页面的标题,现在的浏览器忽略掉了这个参数,所以写啥都没用,url为页面的URL,如果不写的话,就是当前页了。
replaceState(data,title,[,url])
:参数时相同的,这种更改不会访问该URL。也就是不会刷新。会让用户看到的url发生变化,如果我们需要访问该URL,还要去手动的触发。
replaceState不会在window.history里新增历史记录点,其效果类似于window.location.replace(url),都是不会在历史记录点里新增一个记录点的。当你为了响应用户的某些操作,而要更新当前历史记录条目的状态对象或URL时,使用replaceState()方法会特别合适。
PJAX
刚刚我们已经说到了那两个API,我们的PJAX就是基于上面新特性来的。PJAX是别人开发的一个项目,地址是:https://github.com/defunkt/jquery-pjax。
它不仅仅支持了局部刷新这一特点,而且在刷新页面的同时,浏览器地址栏上面的地址是会更改的,用浏览器回退功能也能够回退回去,正常我们用ajax是实现不了的。。
PJAX的基本思路是,当用户点击一个链接,通过ajax更新页面变化的部分,然后使用HTML5的pushState修改浏览器的URL地址,这样有效地避免了整个页面的重新加载。如果浏览器不支持history的两个新API或者JS被禁用了,那这个链接就只能跳转并重新刷新整个页面了。和传统的ajax设计稍微不同,ajax通常是从后台获取JSON数据,然后由前端解析渲染,而PJAX请求的是一个在服务器上生成好的HTML碎片
看看如果我们自己写是怎么样利用这两个API的。
先来看一个完整的例子
demo的地址我放在了http://cailidan.cn/web/demo/testajax这里。
一个很简单的php文件,通过接收不同的id,并且返回不同的数据。显示到textarea上。
1 |
|
下面的例子是这样一个过程:
- 当我们访问index.html的时候,会自动显示成
http://localhost:801/testajax/index.html?page=1
,原因就是我们使用了用history.replaceState更改当前的浏览器历史;并且在textarea部分显示这是一个ajax请求---page1
- 当我们点击每一个li的时候,对应的textarea会发生变化,这没有什么新奇的,但当我们看浏览器的URL,发现对应的url也会发生变化,如
http://localhost:801/testajax/index.html?page=2
这个是我们利用replaceState来做到的。 - 然后我们试一下点击回退,发现是可以回到上一级哒。是不是很棒呢?
- 我们的思路是,先给每个li绑定一个事件,然后当我们点击这个li的时候,调用ajax,并把当前的url拼凑后pushState。当我们首次访问的时候
query=undefined
,我们获取到undefined后,就默认是第一个,此时我们利用replaceState改变状态栏的信息。若状态栏的query有值。,则判断query对应的li是哪个。如果找到了该li,触发其click事件,如果没有的话,证明query传参错误。然后默认去触发第一个。
1 |
|
顺便记录几个XMLHttpRequest的属性
onreadystatechange 每次状态改变所触发事件的事件处理程序。
responseText 从服务器进程返回数据的字符串形式。
responseXML 从服务器进程返回的DOM兼容的文档数据对象。
status 从服务器返回的数字代码,比如常见的404(未找到)和200(已就绪)
status Text 伴随状态码的字符串信息
readyState 对象状态值
0 (未初始化) 对象已建立,但是尚未初始化(尚未调用open方法)
1 (初始化) 对象已建立,尚未调用send方法
2 (发送数据) send方法已调用,但是当前的状态及http头未知
3 (数据传送中) 已接收部分数据,因为响应及http头不全,这时通过responseBody和responseText获取部分数据会出现错误,
4 (完成) 数据接收完毕,此时可以通过通过responseXml和responseText获取完整的回应数据。