深入理解 ajax系列第一篇(XHR 对象)

  1999年,微软公司发布了IE5, 第一次引入新功能:允许javascript 脚本向服务器发起 hffp 请求。这个功能方式并没有被引起注意,知道2004年 Gmail 发布和 Google Map 发布,才引起广泛关注。2005 年2月,ajax 这个词第一次正式提出,指围绕这个功能进行开发一整套做法,从此,ajax称为脚本发起http通信的代名词, W3C也在 2006 年发布了它的国际标准。

概述:

  Ajax是 asynchronous javasricot and XM;L 的简写,中文翻译是异步的 javascript 和 Xml, 这一技术能够向服务器请求额外的数据而无需卸载页面,回带来更好的用户体验,虽然名字中包含 XML,但 ajax 通信与数据格式无关。

  Ajax 包含以下几个步骤:

    1、创建 Ajax 对象

    2、发出 HTTP 请求

    3、接受服务器传回的数据

    4、更新网页的数据

    那么,概括起来就是一句话,Ajax 通过原生的 XMLHttpRequest 对象发送出的 HTTP 请求,得到服务器的数据后,在进行处理

创建:

  ajax 技术的核心是 XMLHttpRequest对象(简称 XHR), 这是由微软收先引入的一个特性,其他浏览器提供商后来都提供了相同的实现,XHR 为向服务器发送请求和解析服务服务器响应提供了流畅的接口,能够以异步方式从服务器取得更多信息,意味着用户单机后,可以不比刷新页面取得新的数据。

  IE5是第一款引入 XHR 对象的浏览器,在 IE5 中,XHR 对象是通过 MSXML 库中的一个 Active 对象实现的,,而IE7+及其他标准浏览器都支持原生的XHR对象

  创建一个 XHR 对象,也叫实例化一个 XHR对象,因为 XMLHTTPRequest() 是一个构造函数,下面是创建 XHR 对象的兼容写法:

  

var xhr:
if(window.XMLHttpRequest){
    xhr = XMLHttpRequest();  
}else{
    xhr = new ActiveXobject("Microsoft.XMLHTTP");
}

  注意:

    如果要建立N个不同的请求,就要手机用不同的 XHR 对象,当然可以重用以存在的 XHR 对象,但这会终止之前该对挂起的任何请求

发送请求:

  open()

    在使用 XHR 对象时,要调用的第一个方法就是 open(),如下所示,该方法接受 3 个参数

xhr.open('get','example.php', false)

    1、open() 方法的第一个参数用于指定发送请求的方式,这个字符串,不区分大小写,但通常使用大写字母,“GET”和“POST”广泛支持

    2、“GET” 是常规请求,它使用与当 URL 完全指定资源,当请求对服务没有任何副作用以及当读物器的响应式可缓存的情况下

    3、“POST” 方发用于 HTML 表单,它在请求主体中包含额外数据且这些数据常存储到服务器上的数据库中,相同的 URL 的重复 POST 请求从服务器得到的响应可能从不同,同时不应该缓存使用这个方法的请求

    4、除了"GET"和"POST"之外,参数还可以是"HEAD"、"OPTIONS"、"PUT"。而由于安全风险的原因,"CONNECT"、"TRACE"、"TRACK"被禁止使用

    

    5、open() 方法的第二个参数是 URL ,该 URL 相对于执行代码的当前页面,且只能向同一个域中使用相同的端口和协议的 URL 发送请求,如果 URL 与启动请求的页面由任何差别,都会引发安全错误

    6、open() 方法的第三个参数是表示是否异步发送请求的布尔值,如果不填写,默认为 True,表示异步发送

    7、如果请求一个收密码保护的 URL 。把用于认证的用户名和密码作为第4和第5参数传递给 open() 方法

  send()

    send() 方法接受一个参数,既要作为请求主体发送的数据,调用 send() 方法后,请求被分到服务器

    如果 "GET" 方法, send() 方法无参数,或参数为 null ,如果是 post 方法,send() 方法的参数为要发送的数据

      

xhr.open('GET', 'example.php', false);
xhr.send(null);

接收响应:

    一个完整的 HTTP 响应由状态码、响应头集合和响应主题组成,在收到响应后,这些都可以通过 XHR 对象的属性和方法使用,主要有以下 4 个属性:

  

responseText : 作为响应主体被返回的文本(文本形式)
responseXML: 如果响应的内同类型是 “text/xml” 或者 “application/xml”,这个属性中将保存着响应数据的 XML ,DOM文档(document形式)
status:HTTP 状态码(数字形式)
statusText:HTTP状态说明(文本形式)

  在所接收响应后,第一步是检查 status 属性,以确定响应已经成功返回。一般来说,可以将 HTTP 状态码为200最为成功的标志。此时,responseText 属性的内容已经就绪,而且在内容类型正确的情况下,responseXML 也可以访问了,此外,状态码为 304 表示请求的资源并没有被修改,可以直接使用浏览器中缓存的版本;当然,也意味着响应是有效的

  无论内容类型是什么,响应主体的内容都会保存到responseText 属性中,而对于 XML 数据而言,responseXML 属性的值将为 null

if(xhr.status >= 200 && xhr.status == 304){
    alert(xhr.responseTEXT);
}else{
    alert("request was unsuccessful:"+ xhr.status);    
}

同步:

  如果接收的是同步的响应,则需要将 open() 方法的第三个参数设置为 false,那么 send() 方法将阻塞直到请求完成,一旦 send() 方法返回,仅需要奸臣 XHR 对象的 status 和 responseText 属性即可

  同步请求是吸引人的,但应该避免使用他们,客户端 javascriot 是单线程的,当 send() 方法阻塞时,它通常会导致整个浏览器 UI 冻结,如果连接的服务器响应慢,那么用户的浏览器将冻结

<button id="btn">获取信息</button>
<div id="result"></div>
<script>
btn.onclick = function(){
    //创建xhr对象
    var xhr;
    if(window.XMLHttpRequest){
        xhr = new XMLHttpRequest();
    }else{
        xhr = new ActiveXObject('Microsoft.XMLHTTP');
    }
    //发送请求
    xhr.open('get','/uploads/rs/26/ddzmgynp/message.xml',false);
    xhr.send();
    //同步接受响应
    if(xhr.readyState == 4){
        if(xhr.status == 200){
            //实际操作
            result.innerHTML += xhr.responseText;
        }
    }
}
</script>   

异步:

  如果需要接收的时异步请求,这就需要检测 XHR 对象的readyStatus 属性,该属性表示请求/响应过程的当前活动阶段,这个属性可取的值如下:

  

0(UNSEND):未初始化,尚未调用 open() 方法
1(OPENED):启动,已经调用 open()方法,但尚且 send() 方法
2(HEADERS_RECEIVED):发送,已经调用dend() 方法,且接收到头信息
3(LOADING):接收,已经接收到部分响应主体信息
4(DONE):完成,已经接收到全部响应数据,二七五已经可以客户端使用了

  理论上,只要 readyStatus 属性值有一个值编程另外一个值,都会触发一次 readyStatusChange事件。可以利用这个时间检测每次状态变化后 readyStatus 的值。通常,我们对 readyStatus 的值为4 的阶段甘心去,应为着意味着所哟数据都已经就绪

  注意:
    必须在调用 open() 之前指定 onreadyStatuschange 时间处理程序才能确保浏览器兼容性,否则将无法接收 readyStatus 属性为 0 和 1 的情况

xhr.onreadystatechange = function(){
    if(xhr.readyState === 4){
        if(xhr.status == 200){
            alert(xhr.responseText);
        }
    }
}
<button id="btn">获取信息</button>
<div id="result"></div>
<script>
btn.onclick = function(){
    //创建xhr对象
    var xhr;
    if(window.XMLHttpRequest){
        xhr = new XMLHttpRequest();
    }else{
        xhr = new ActiveXObject('Microsoft.XMLHTTP');
    }
    //异步接受响应
    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4){
            if(xhr.status == 200){
                //实际操作
                result.innerHTML += xhr.responseText;
            }
        }
    }
    //发送请求
    xhr.open('get','message.xml',true);
    xhr.send();
}
</script>    

超时:

  XHR对象的 timeout 属性等于一个整数,表示多少毫秒后,如果请求仍然没有得到结果,就会自动终止,该属性默认等于 0, 表示没有时间限制

  如果请求超时, 将触发 ontimeout 事件

  注意:

     IE8 浏览器不支持该属性

  

xhr.open("post", 'test.php', true)
xhr.ontimeout = function(){
    console.log("The request timeed out !!! ")
}

xhr.timeout = 1000,
xhr.send();

优化:

   使用Ajax 接收数据时,由于网络和数据大小的原因,并不时立刻就可以在页面中显示出来,所以,更好的做法是,在接收数据的过程中,显示一个类似 loading 的小图片,并且禁用按钮,当数据完全接收后,在隐藏给图片,并开启按钮:

<button id="btn">获取信息</button>
<img id="img" height="16" style="display:none" src="data:image/gif;base64,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" alt="loading">
<div id="result"></div>
<script>
var add = (function(){
    var counter = 0;
    return function(){
        return ++counter;
    }
})();
btn.onclick = function(){
    img.style.display = 'inline-block';
    btn.setAttribute('disabled','');
    //创建xhr对象
    var xhr;
    if(window.XMLHttpRequest){
        xhr = new XMLHttpRequest();
    }else{
        xhr = new ActiveXObject('Microsoft.XMLHTTP');
    }
    //异步接受响应
    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4){
            if(xhr.status == 200){
              img.style.display = 'none';
              btn.removeAttribute('disabled');
              var data = JSON.parse(xhr.responseText);
              var sum = add() - 1;
              if(sum < data.length){
                result.innerHTML += data[sum];    
              }
            }
        }
    }
    //发送请求
    xhr.open('get','data.php',true);
    xhr.send();
}
</script>      

  Ajax 前端本身的内容并不难,但是,由于Ajax 涉及到一些后端及网络的只是,使得学起来不是很容易。

本文摘自:https://www.cnblogs.com/xiaohuochai/p/6036475.html

  

   

  

  

原文地址:https://www.cnblogs.com/jcjc/p/11573946.html