深入学习 Ajax

  • XMLHttpRequest 对象
  • XHR的用法
    • 同步请求
    • 异步请求 - onreadystatechange 事件
  • 进度事件
    • 接收结束 - load事件
    • 进度条 - progress事件
  • 关于 HTTP 头部信息
    • 修改请求头部信息
    • 获取响应头部信息
  • 请求类型
    • GET 请求
    • POST 请求
    • FormData

Ajax 技术的核心是XMLHttpRequest 对象(简称XHR),XHR能够以异步方式从服务器取得更多信息,意味着用户单击后,可以不必刷新页面也能取得新数据。
虽然名字中包含XML 的成分,但Ajax 通信与数据格式无关;这种技术就是无须刷新页面即可从服务器取得数据,但不一定是XML 数据。

XMLHttpRequest 对象

IE7+FirefoxOperaChromeSafari 都支持原生的XHR 对象,可以像下面这样使用XMLHttpRequest构造函数(IE7-的版本这里就不写了)

var xhr = new XMLHttpRequest();

XHR的用法

在使用XHR 对象时,要调用的第一个方法是open(),它接受3 个参数:
要发送的请求的类型("get""post"等)、请求的URL 和表示是否异步发送请求的布尔值(值为 false 时为同步请求)。

同步请求

xhr.open("get", "tet.json", false);

有关这行代码,需要说明两点:
一是URL相对于执行代码的当前页面(当然也可以使用绝对路径);
二是调用open()方法并不会真正发送请求,而只是启动一个请求以备发送。
要发送特定的请求,必须像下面这样调用send()方法

xhr.open("get", "tet.json", false);
xhr.send(null);

这里的send()方法接收一个参数,即要作为请求主体发送的数据。如果不需要通过请求主体发送数据,则必须传入null,因为这个参数对有些浏览器来说是必需的。
调用send()之后,请求就会被分派到服务器。
由于这次请求是同步的,JavaScript 代码会等到服务器响应之后再继续执行。在收到响应后,响应
的数据会自动填充XHR 对象的属性,相关的属性简介如下。

responseText:获得字符串形式的响应数据。
responseXML:如果响应的内容类型是"text/xml"或"application/xml",这个属性中将获得 XML 形式的响应数据。对于非XML 数据而言,responseXML 属性的值将为null。
status:响应的HTTP 状态。
statusText:HTTP 状态的说明。

在接收到响应后,第一步是检查status 属性,以确定响应已经成功返回。
一般来说,可以将HTTP状态代码200作为成功的标志。此时,responseText 属性的内容已经就绪。此外,状态代码304表示请求的资源并没有被修改,可以直接使用浏览器中缓存的版本,也意味着响应是有效的。为确保接收到适当的响应,应该像下面这样检查上述这两种状态代码:

if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){console.log(xhr,'\n'+xhr.response);
} else {console.log("请求错误: " + xhr.status);
}

所以一个完整的同步请求代码如下:

var xhr = new XMLHttpRequest();
xhr.open('get','./test.json',false);
xhr.send(null);if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){console.log(xhr,'\n'+xhr.response);
} else {console.log("请求错误: " + xhr.status);
}

异步请求 - onreadystatechange 事件

xhr.open("get", "tet.json", true);

open() 方法的第三个参数为 true 时,执行的是异步请求,多数情况下,我们还是要发送异步请求,才能让 JavaScript继续执行而不必等待响应。此时,可以检测XHR 对象readyState 属性,该属性表示请求/响应过程的当前活动阶段。这个属性可取的值如下。

0:未初始化。尚未调用open()方法。
1:启动。已经调用open()方法,但尚未调用send()方法。
2:发送。已经调用send()方法,但尚未接收到响应。
3:接收。已经接收到部分响应数据。
4:完成。已经接收到全部响应数据,而且已经可以在客户端使用了。

只要readyState 属性的值由一个值变成另一个值,都会触发一次readystatechange 事件。可以利用这个事件来检测每次状态变化后readyState 的值。通常,我们只对readyState 值为4 的阶段感兴趣,因为这时所有数据都已经就绪。不过,必须在调用open()之前指定onreadystatechange事件处理程序才能确保跨浏览器兼容性。下面来看一下异步请求的写法:

var xhr = new XMLHttpRequest();xhr.onreadystatechange = function(){console.log(xhr.readyState);if (xhr.readyState == 4){if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){console.log(xhr,'\n'+xhr.responseText);} else {console.log("请求错误: " + xhr.status);}}
};xhr.open('get','./test.json',true);
xhr.send(null);


以上代码利用DOM 0 级方法为XHR 对象添加了事件处理程序,原因是并非所有浏览器都支持DOM 2级方法。与其他事件处理程序不同,这里没有向onreadystatechange事件处理程序中传递event对象;必须通过XHR 对象本身来确定下一步该怎么做。

另外,在接收到响应之前还可以调用abort()方法来取消异步请求,如下所示:

xhr.abort();

调用这个方法后,XHR 对象会停止触发事件,而且也不再允许访问任何与响应有关的对象属性。

进度事件

接收结束 - load事件

有以下6 个进度事件。

loadstart:在接收到响应数据的第一个字节时触发。
progress:在接收响应期间持续不断地触发。
error:在请求发生错误时触发。
abort:在因为调用abort()方法而终止连接时触发。
load:在接收到完整的响应数据时触发。
loadend:在通信完成或者触发error、abort 或load 事件后触发。

每个请求都从触发loadstart 事件开始,接下来是一或多个progress 事件,然后触发errorabortload 事件中的一个,最后以触发loadend 事件结束。
支持前5 个事件的浏览器有Firefox 3.5+、Safari 4+、Chrome、iOS 版Safari 和Android 版WebKitOpera(从第11 版开始)IE 8+只支持load 事件。目前还没有浏览器支持loadend 事件
所以这里只介绍一下 load 事件progress事件

load 事件可用以替代readystatechange 事件。响应接收完毕后将触发load 事件,因此也就没有必要去检查readyState 属性了。

var xhr = new XMLHttpRequest();
xhr.onload = function(){if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){console.log(xhr,'\n'+xhr.responseText);} else {console.log("请求错误: " + xhr.status);}
};
xhr.open("get", "./test.json", true);
xhr.send(null);

进度条 - progress事件

progress 事件会在浏览器接收新数据期间周期性地触发。而onprogress 事件处理程序会接收到一个event 对象,其target 属性XHR 对象。下面展示了为用户创建进度指示器的一个示例。
为确保正常执行,必须在调用open()方法之前添加onprogress 事件处理程序。

var xhr = new XMLHttpRequest();
xhr.onprogress = function(event){if (event.lengthComputable){console.log(event)}
};
xhr.open("get", "./test.json", true);
xhr.send(null);


上图中包含了总数,请求过程中已请求的数据,打印时候的时间等信息,根据这些信息可以轻易地实现进度条效果。

关于 HTTP 头部信息

每个HTTP请求和响应都会带有相应的头部信息,其中有的对开发人员有用,有的也没有什么用。
XHR 对象也提供了操作这两种头部(即请求头部响应头部)信息的方法。

修改请求头部信息

默认情况下,在发送XHR 请求的同时,还会发送下列头部信息。

Accept:浏览器能够处理的内容类型。
Accept-Charset:浏览器能够显示的字符集。
Accept-Encoding:浏览器能够处理的压缩编码。
Accept-Language:浏览器当前设置的语言。
Connection:浏览器与服务器之间连接的类型。
Cookie:当前页面设置的任何Cookie。
Host:发出请求的页面所在的域 。
Referer:发出请求的页面的URI。
User-Agent:浏览器的用户代理字符串。


虽然不同浏览器实际发送的头部信息会有所不同,但以上列出的基本上是所有浏览器都会发送的。
使用setRequestHeader()方法可以设置自定义的请求头部信息。
这个方法接受两个参数:头部字段的名称和头部字段的值。
要成功发送请求头部信息,必须在调用open()方法之后且调用send()方法之前调用setRequestHeader(),如下面的例子所示:

var xhr = new XMLHttpRequest();xhr.onreadystatechange = function(){console.log(xhr.readyState);if (xhr.readyState == 4){if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){console.log(xhr,'\n'+xhr.responseText);} else {console.log("请求错误: " + xhr.status);}}
};xhr.open('get','./test.json',true);
xhr.setRequestHeader("MyHeader", "MyValue");
xhr.send(null);


服务器在接收到这种自定义的头部信息之后,可以执行相应的后续操作。我们建议读者使用自定义的头部字段名称,不要使用浏览器正常发送的字段名称,否则有可能会影响服务器的响应。有的浏览器允许开发人员重写默认的头部信息,但有的浏览器则不允许这样做。

获取响应头部信息

调用XHR 对象getResponseHeader()方法并传入头部字段名称,可以取得相应的响应头部信息。而调用getAllResponseHeaders()方法则可以取得一个包含所有头部信息的长字符串。来看下面的例子。

var xhr = new XMLHttpRequest();xhr.onreadystatechange = function(){if (xhr.readyState == 4){if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){var contentType = xhr.getResponseHeader("content-type");var allHeaders = xhr.getAllResponseHeaders();console.log(contentType+'\n\n',allHeaders);} else {console.log("请求错误: " + xhr.status);}}
};xhr.open('get','./test.json',true);
xhr.setRequestHeader("MyHeader", "MyValue");
xhr.send(null);


请求类型

GET 请求

GET是最常见的请求类型,最常用于向服务器查询某些信息。必要时,可以将查询字符串参数追加到URL的末尾,以便将信息发送给服务器。对XHR 而言,位于传入open()方法URL 末尾的查询字符串必须经过正确的编码才行。
使用GET 请求经常会发生的一个错误,就是查询字符串的格式有问题。查询字符串中每个参数的名称和值都必须使用encodeURIComponent()进行编码,然后才能放到URL 的末尾;而且所有名-值对
儿都必须由和号(&)分隔,如下面的例子所示。

xhr.open("get", "./test.json?name1=value1&name2=value2", true);

下面这个函数可以辅助向现有URL 的末尾添加查询字符串参数:

function addURLParam(url, name, value) {url += (url.indexOf("?") == -1 ? "?" : "&");url += encodeURIComponent(name) + "=" + encodeURIComponent(value);return url;
}
//下面是使用这个函数来构建请求URL 的示例。
var url = "./test.json";
//添加参数
url = addURLParam(url, "name", "RunSky87");
url = addURLParam(url, "age", 24);
//初始化请求
xhr.open("get", url, true);

这个addURLParam()函数接受三个参数:要添加参数的URL、参数的名称和参数的值。这个函数
首先检查URL 是否包含问号(以确定是否已经有参数存在)。如果没有,就添加一个问号;否则,就添
加一个和号。然后,将参数名称和值进行编码,再添加到URL 的末尾。最后返回添加参数之后的URL。

在上面的例子中,您可能得到的是缓存的结果。可以向 URL 添加一个唯一的 ID 解决这个问题:

xhr.open("get", "./test.json?name1=value1&name2=value2&t=" + Math.random(), true);

POST 请求

POST 请求通常用于向服务器发送应该被保存的数据。POST 请求的主体可以包含非常多的数据,而且格式不限。在open()方法第一个参数的位置传入"post",就可以初始化一个POST 请求,如下面的例子所示。

xhr.open("post", "./test.json", true);

发送POST请求的第二步就是向send()方法中传入某些数据。由于XHR最初的设计主要是为了处理XML,因此可以在此传入XML DOM 文档,传入的文档经序列化之后将作为请求主体被提交到服务器。当然,也可以在此传入任何想发送到服务器的字符串。
默认情况下,服务器对POST 请求和提交Web 表单的请求并不会一视同仁。因此,服务器端必须有程序来读取发送过来的原始数据,并从中解析出有用的部分。
不过,我们可以使用XHR来模仿表单提交:首先将Content-Type头部信息设置为application/x-www-form-urlencoded,也就是表单提交时的内容类型,其次是以适当的格式创建一个字符串。这里如果不设置Content-Type头部信息,服务器想要获取数据就要做一些操作。

<form id="input" name="input" action="{{请求的url}}" method="post">Username: <input type="text" name="username" value="admin">Password: <input type="password" name="password" value="111111"><input type="submit" value="Submit">
</form>

下面的写法可以模仿上面的表单提交:

var xhr = new XMLHttpRequest();xhr.onreadystatechange = function(){if (xhr.readyState == 4){if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){console.log("请求成功");} else {console.log("请求错误: " + xhr.status);}}
};xhr.open('post','{{请求的url}}',true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send('username=admin&password=111111');

FormData

说到这里就不得不提一下 FormData 对象。
FormData为序列化表单以及创建与表单格式相同的数据(用于通过XHR 传输)提供了便利。下面的代码创建了一个FormData 对象,并向其中添加了一些数据。
使用FormData 的方便之处体现在不必明确地在XHR 对象上设置请求头部。XHR 对象能够识别传入的数据类型是FormData的实例,并配置适当的头部信息。

var data = new FormData();
data.append("username", "admin");

这个append()方法接收两个参数:,分别对应表单字段的名字和字段中包含的值。可以像这样添加任意多个键值对儿。而通过向FormData 构造函数中传入表单元素,也可以用表单元素的数据预先向其中填入键值对儿:

var data = new FormData(document.forms[0]);

创建了FormData 的实例后,可以将它直接传给XHR 的send()方法,,上面的 POST 可以写成下面的形式:

var xhr = new XMLHttpRequest();xhr.onreadystatechange = function(){if (xhr.readyState == 4){if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){console.log("请求成功");} else {console.log("请求错误: " + xhr.status);}}
};var data= new FormData();
data.append("username", "admin");
data.append("password", "111111");
xhr.open('post','{{请求的url}}',true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send(data);

JavaScript--20 深入理解 Ajax相关推荐

  1. 回调函数举例ajax,通过回调函数的理解来进一步理解ajax及其注意的用法

    一,再一次理解回调函数 (function($){ $.fn.shadow = function(opts){ //定义的默认的参数 var defaults = { copies: 5, opaci ...

  2. 我对javascript对象的理解

    前言 JavaScript这门语言除了基本类型都是对象,可以说JavaScript核心就是对象,因此理解JavaScript对象及其种种特性至关重要,这是内功.本文介绍了我对es5对象,原型, 原型链 ...

  3. java中使用ajax请求数据格式,Java基本数据类型 javascript中post和ajax提交 Axure

    Java基本数据类型 Java一共有八种基本类型,六种数据类型,一种字符类型,一种布尔类型 分别是 byte 是数据类型内存大小1,内存位数是8位,最小值是-128(-27),最大值:127(27-1 ...

  4. javascript之异步操作理解---回调函数,async,await以及promise对象

    javascript之异步操作理解---回调函数,async,await以及promise对象 概述 概述 写在前面:虽然平时做项目,但是发现自己写的代码还是很烂.最近接触了一个对性能要求比较高的项目 ...

  5. 【javascript】深入理解对象

    为什么80%的码农都做不了架构师?>>>    今天学习的主题是 JavaScript对象. 要创建一个JavaScript对象大家应该都觉得很简单,直接写上一行 var obj = ...

  6. JavaScript面向对象——深入理解寄生组合继承

    JavaScript面向对象--深入理解寄生组合继承 之前谈到过组合继承,会有初始化两次实例方法/属性的缺点,接下来我们谈谈为了避免这种缺点的寄生组合继承 寄生组合继承: 思路:组合继承中,构造函数继 ...

  7. JavaScript面向对象——深入理解原型继承

    JavaScript继承--深入理解原型继承 原型继承 // 父类function School (name, address) {this.name = namethis.address = add ...

  8. 【Javascript】深入理解this作用域问题以及new/let/var/const对this作用域的影响

    理解this作用域 <javascript高级程序设计>中有说到: this对象是在运行时基于函数的执行环境绑定的:在全局函数中,this等于window,而当函数被作为某个对象调用时,t ...

  9. Javascript闭包简单理解

    Javascript闭包简单理解 原文:Javascript闭包简单理解 提到闭包,想必大家都早有耳闻,下面说下我的简单理解. 说实话平时工作中实际手动写闭包的场景并不多,但是项目中用到的第三方框架和 ...

  10. JavaScript之全面理解面向对象的JS

    今天看到一篇文章写得很好,对于像博主这种js一般级别的菜鸟很有帮助,博主秉着"好文要转"的原则收藏了这篇文章,简单排了下版,分享给大家,本文转自原文:http://www.ibm. ...

最新文章

  1. 高中生也能读懂的Docker入门教程
  2. sshpass连接主机以及执行命令
  3. Reference和ReferenceQueue
  4. 自动化部署脚本开启所有zookpeer等服务
  5. SpringCloud Ribbon实战以及Ribbon随机策略RandomRule的源码浅析(六)
  6. poatman32位下载_Postman.dll下载|Postman.dll下载官方版【32位|64位】-太平洋下载中心...
  7. Smarty 获取当前日期时间和格式化日期时间
  8. moba的m是什么意思_moba游戏是什么
  9. Sqlite加密问题
  10. sharepoint搭建文档服务器,SharePoint Server教程
  11. SQL获取当天0点0分0秒和23点59分59秒方法
  12. MSP430第三十二章:Comp_B
  13. idea报错 Result Maps collection does not contain value for com.
  14. 影视后期制作课题报告
  15. (转载)使用Android Studio对代码进行重构
  16. ES6对数组进行正序和倒序排列
  17. 硬核:如何用「区块链」改进传染病监测预警网络?
  18. C++边边角角(一)
  19. redmine2.0 + mongrel
  20. 【心得体会】2022年华为杯数学建模比赛参赛心得体会

热门文章

  1. 怎么改变计算机的黑屏,电脑调整分辨率最大会黑屏的解决方法
  2. Mac数据恢复首选easyrecovery
  3. 陀螺年度好文回顾|区块链跨链互操性的意义和应用案例
  4. Android Studio 微信分享功能(包括可以分享到朋友圈,分享到朋友)
  5. js中判断对象是否为空
  6. 甘特图(别名:横道图、条状图)的画法
  7. C++习题:6-1 CCircle And CCylinder
  8. 高等数学学习笔记——第四十九讲——一阶常微分方程的求解
  9. Android SIM卡联系人操作总结
  10. Python猴子摘香蕉问题