你真的懂ajax吗?

前言

总括: 本文讲解了ajax的历史,工做原理以及优缺点,对XMLHttpRequest对象进行了详细的讲解,并使用原生js实现了一个ajax对象以方便平常开始使用。javascript

古之立大事者,不唯有超世之才,亦必有坚忍不拔之志。前端

正文

相信每一个前端程序员平常工做中都避免不了的工做就是和后端联调,联调天然就避免不了使用ajax,但我相信,无论是使用jquery封装的ajax方法仍是使用vue的插件vue-resource的程序员,真正对于ajax有过深刻探究的并很少,咱们更多的是为了使用而使用,至于它的原理每每由于即便不了解依旧能作出东西而懒得去看,咱们都被轮子们惯坏了。根据二八定律,即任何一组东西中,最重要的只占其中一小部分,约20%,其他80%的尽管是多数,倒是次要的。因 此,若是想挤进那20%的行列,就要学到通常人学不到的深度,学到通常人学不了的东西。vue

好的,如今咱们从头来讲一下ajaxjava

Ajax简介

在上世纪90年代,几乎全部的网站都由HTML页面实现,服务器处理每个用户请求都须要从新加载网页。形式是怎样的呢?就好比说你在浏览器上登陆本身的微博帐号,填完了表单,点击登陆按钮,一次"完整"的HTTP请求就此触发,服务器发现你的登陆密码不对头,立马把网页原本来本的返回给你,在用户看来呢,就是一次从新加载的过程!用户体验极差!并且这个作法浪费了许多带宽,由于在先后两个页面中的大部分HTML码每每是相同的。因为每次应用的沟通都须要向服务器发送请求,应用的回应时间依赖于服务器的回应时间。这致使了用户界面的回应比本机应用慢得多。jquery

到了2005年,google率先在它的应用(诸如google地图、gmail)里使用了ajax技术,这才让这项技术正式风靡开来。git

现在它的应用已经十分普遍:程序员

Ajax工做原理

 Ajax的工做原理至关于在用户和服务器之间加了一个中间层(ajax引擎),使用户操做与服务器响应异步化。并非全部的用户请求都提交给服务器,像—些数据验证(好比判断用户是否输入了数据)和数据处理(好比判断用户输入数据是不是数字)等都交给Ajax引擎本身来作, 只有肯定须要从服务器读取新数据时再由Ajax引擎代为向服务器提交请求。把这些交给了Ajax引擎,用户操做起来也就感受更加流畅了。github

Ajax优缺点

Ajax的优势

  1. 无刷新更新数据。

AJAX最大优势就是能在不刷新整个页面的前提下与服务器通讯维护数据。这使得Web应用程序更为迅捷地响应用户交互,并避免了在网络上发送那些没有改变的信息,减小用户等待时间,带来很是好的用户体验。

2.异步与服务器通讯。

AJAX使用异步方式与服务器通讯,不须要打断用户的操做,具备更加迅速的响应能力。优化了Browser和Server之间的沟通,减小没必要要的数据传输、时间及下降网络上数据流量。

3.前端和后端负载平衡。

AJAX能够把之前一些服务器负担的工做转嫁到客户端,利用客户端闲置的能力来处理,减轻服务器和带宽的负担,节约空间和宽带租用成本。而且减轻服务器的负担,AJAX的原则是“按需取数据”,能够最大程度的减小冗余请求和响应对服务器形成的负担,提高站点性能。

4.基于标准被普遍支持。

AJAX基于标准化的并被普遍支持的技术,不须要下载浏览器插件或者小程序,但须要客户容许JavaScript在浏览器上执行。随着Ajax的成熟,一些简化Ajax使用方法的程序库也相继问世。一样,也出现了另外一种辅助程序设计的技术,为那些不支持JavaScript的用户提供替代功能。

5.界面与应用分离。

Ajax使WEB中的界面与应用分离(也能够说是数据与呈现分离),有利于分工合做、减小非技术人员对页面的修改形成的WEB应用程序错误、提升效率、也更加适用于如今的发布系统。

Ajax缺点

  1. AjAX干掉了Back和加入收藏书签功能,即对浏览器机制的破坏。

对应用Ajax最主要的批评就是,它可能破坏浏览器的后退与加入收藏书签功能。在动态更新页面的状况下,用户没法回到前一个页面状态,这是由于浏览器仅能记下历史记录中的静态页面。一个被完整读入的页面与一个已经被动态修改过的页面之间的可能差异很是微妙;用户一般都但愿单击后退按钮,就可以取消他们的前一次操做,可是在Ajax应用程序中,却没法这样作。不过开发者已想出了种种办法来解决这个问题,HTML5 以前的方法大可能是在用户单击后退按钮访问历史记录时,经过建立或使用一个隐藏的IFRAME来重现页面上的变动。(例如,当用户在Google Maps中单击后退时,它在一个隐藏的IFRAME中进行搜索,而后将搜索结果反映到Ajax元素上,以便将应用程序状态恢复到当时的状态)。

关于没法将状态加入收藏或书签的问题,HTML5以前的一种方式是使用URL片段标识符(一般被称为锚点,即URL中#后面的部分)来保持追踪,容许用户回到指定的某个应用程序状态。(许多浏览器容许JavaScript动态更新锚点,这使得Ajax应用程序可以在更新显示内容的同时更新锚点。)HTML5 之后能够直接操做浏览历史,并以字符串形式存储网页状态,将网页加入网页收藏夹或书签时状态会被隐形地保留。上述两个方法也能够同时解决没法后退的问题。

2.AJAX的安全问题。

AJAX技术给用户带来很好的用户体验的同时也对IT企业带来了新的安全威胁,Ajax技术就如同对企业数据创建了一个直接通道。这使得开发者在不经意间会暴露比之前更多的数据和服务器逻辑。Ajax的逻辑能够对客户端的安全扫描技术隐藏起来,容许黑客从远端服务器上创建新的攻击。还有Ajax也难以免一些已知的安全弱点,诸如跨站点脚步攻击、SQL注入攻击和基于Credentials的安全漏洞等等。

3.由于网络延迟须要给用户提供必要提示

进行Ajax开发时,网络延迟——即用户发出请求到服务器发出响应之间的间隔——须要慎重考虑。若是不给予用户明确的回应,没有恰当的预读数据,或者对XMLHttpRequest的不恰当处理,都会使用户感到厌烦。一般的解决方案是,使用一个可视化的组件来告诉用户系统正在进行后台操做而且正在读取数据和内容。

XMLhttpRequest介绍

Ajax(Asynchronous JavaScript and XML)不是指一种单一的技术,而是有机地利用了一系列相关的技术。虽然其名称包含XML,但实际上数据格式能够由JSON代替,进一步减小数据量,造成所谓的AJAJ。为了使用JavaScript向服务器发出 HTTP 请求,须要一个提供此功能的类的实例。这就是XMLHttpRequest的由来。这样的类最初是在Internet Explorer中做为一个名为XMLHTTP的ActiveX对象引入的。而后,Mozilla,Safari和其余浏览器,实现一个XMLHttpRequest类,支持Microsoft的原始ActiveX对象的方法和属性。同时微软也实现了XMLHttpRequest。

显而易见XMLHttpRequest类是重中之重了。

XMLhttpRequest属性

onreadystatechange

一个JavaScript函数对象,当readyState属性改变时会调用它。回调函数会在user interface线程中调用。

readyState

HTTP 请求的状态.当一个 XMLHttpRequest 初次建立时,这个属性的值从 0 开始,直到接收到完整的 HTTP 响应,这个值增长到 4。

5 个状态中每个都有一个相关联的非正式的名称,下表列出了状态、名称和含义:

状态 名称 描述
0 Uninitialized 初始化状态。XMLHttpRequest 对象已建立或已被 abort() 方法重置。
1 Open open() 方法已调用,可是 send() 方法未调用。请求尚未被发送。
2 Sent Send() 方法已调用,HTTP 请求已发送到 Web 服务器。未接收到响应。
3 Receiving 全部响应头部都已经接收到。响应体开始接收但未完成。
4 Loaded HTTP 响应已经彻底接收。

readyState 的值不会递减,除非当一个请求在处理过程当中的时候调用了 abort() 或 open() 方法。每次这个属性的值增长的时候,都会触发 onreadystatechange 事件句柄。

responseText

目前为止为服务器接收到的响应体(不包括头部),或者若是尚未接收到数据的话,就是空字符串。

若是 readyState 小于 3,这个属性就是一个空字符串。当 readyState 为 3,这个属性返回目前已经接收的响应部分。若是 readyState 为 4,这个属性保存了完整的响应体。

若是响应包含了为响应体指定字符编码的头部,就使用该编码。不然,假定使用 Unicode UTF-8。

responseXML

对请求的响应,解析为 XML 并做为 Document 对象返回。

status

由服务器返回的 HTTP 状态代码,如 200 表示成功,而 404 表示 "Not Found" 错误。当 readyState 小于 3 的时候读取这一属性会致使一个异常。

statusText

这个属性用名称而不是数字指定了请求的 HTTP 的状态代码。也就是说,当状态为 200 的时候它是 "OK",当状态为 404 的时候它是 "Not Found"。和 status 属性同样,当 readyState 小于 3 的时候读取这一属性会致使一个异常。

XMLHttpRequest方法

abort()

取消当前响应,关闭链接而且结束任何未决的网络活动。

这个方法把 XMLHttpRequest 对象重置为 readyState 为 0 的状态,而且取消全部未决的网络活动。例如,若是请求用了太长时间,并且响应再也不必要的时候,能够调用这个方法。

getAllResponseHeaders()

把 HTTP 响应头部做为未解析的字符串返回。

若是 readyState 小于 3,这个方法返回 null。不然,它返回服务器发送的全部 HTTP 响应的头部。头部做为单个的字符串返回,一行一个头部。每行用换行符 "\r\n" 隔开。

getResponseHeader()

返回指定的 HTTP 响应头部的值。其参数是要返回的 HTTP 响应头部的名称。可使用任何大小写来制定这个头部名字,和响应头部的比较是不区分大小写的。

该方法的返回值是指定的 HTTP 响应头部的值,若是没有接收到这个头部或者 readyState 小于 3 则为空字符串。若是接收到多个有指定名称的头部,这个头部的值被链接起来并返回,使用逗号和空格分隔开各个头部的值。

open()

初始化一个请求. 该方法用于JavaScript代码中;若是是本地代码, 使用 openRequest()方法代替.

注意: 在一个已经激活的request下(已经调用open()或者openRequest()方法的request)再次调用这个方法至关于调用了abort()方法。

参数

  • method

    请求所使用的HTTP方法; 例如 "GET", "POST", "PUT", "DELETE"等. 若是下个参数是非HTTP(S)的URL,则忽略该参数.

  • url

    该请求所要访问的URL

  • async

    一个可选的布尔值参数,默认为true,意味着是否执行异步操做,若是值为false,则send()方法不会返回任何东西,直到接受到了服务器的返回数据。若是为值为true,一个对开发者透明的通知会发送到相关的事件监听者。这个值必须是true,若是multipart 属性是true,不然将会出现一个意外。

  • user

    用户名,可选参数,为受权使用;默认参数为空string.

  • password

    密码,可选参数,为受权使用;默认参数为空string.

send()

发送 HTTP 请求,使用传递给 open() 方法的参数,以及传递给该方法的可选请求体。

setRequestHeader()

向一个打开但未发送的请求设置或添加一个 HTTP 请求(设置请求头)。

参数

  • header

    将要被赋值的请求头名称

  • value

    给指定的请求头赋的值

Ajax原生js实现

下面是使用原生js写的ajax:

var ajax = {};
ajax.httpRequest = function () {
    //判断是否支持XMLHttpRequest对象
    if (window.XMLHttpRequest) {
        return new XMLHttpRequest();
    }
    //兼容IE浏览器
    var versions = [
        "MSXML2.XmlHttp.6.0",
        "MSXML2.XmlHttp.5.0",
        "MSXML2.XmlHttp.4.0",
        "MSXML2.XmlHttp.3.0",
        "MSXML2.XmlHttp.2.0",
        "Microsoft.XmlHttp"
    ];
    //定义局部变量xhr,储存IE浏览器的ActiveXObject对象
    var xhr;
    for (var i = 0; i < versions.length; i++) {
        try {
            xhr = new ActiveXObject(versions[i]);
            break;
        } catch (e) {
        }
    }
    return xhr;
};

ajax.send = function (url, callback, method, data, async) {
    //默认异步
    if (async === undefined) {
        async = true;
    }
    var httpRequest = ajax.httpRequest();
    //初始化HTTP请求
    httpRequest.open(method, url, async);
    //onreadystatechange函数对象
    httpRequest.onreadystatechange = function () {
        //readyState 的值等于4,从服务器拿到了数据
        if (httpRequest.readyState == 4) {
            //回调服务器响应数据
            callback(httpRequest.responseText)
        }
    };
    if (method == 'POST') {
        //给指定的HTTP请求头赋值
        httpRequest.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    }
    //发送HTTP请求
    httpRequest.send(data);
};
//实现GET请求
ajax.get = function (url, data, callback, async) {
    var query = [];
    for (var key in data) {
        query.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]));
    }
    ajax.send(url + (query.length ? '?' + query.join('&') : ''), callback, 'GET', null, async)
};
//实现POST请求
ajax.post = function (url, data, callback, async) {
    var query = [];
    for (var key in data) {
        query.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]));
    }
    ajax.send(url, callback, 'POST', query.join('&'), async)
};

若是你使用jquery或是zepto很大部分是由于它的ajax兼容性高的缘故,不妨试试这个:damonare的ajax库,喜欢给个star也是能够的。

后记

ajax技术对于整个web应用意义都是非凡的,仅以此篇致敬那些曾经奋斗在一线为了ajax技术的实现和普及作出工做的前辈们。

参考文章

相关文章
相关标签/搜索