转载
https://blog.csdn.net/l_ppp/article/details/108921610
https://blog.csdn.net/l_ppp/article/details/108921610
对于Ajax,肯定很多小伙伴都听过甚至用过了,那么没听过的也不用着急,本文会对Ajax进行讲解,其次,一定还有一些人只用过JQuery封装好了的Ajax却对原生的Ajax并不了解,那么也不用着急,本文从最基本的Ajax开始讲起,然后最后会尽可能得模仿JQuery对其进行封装,让我刚才提到的两类人能对Ajax有进一步的了解。
- 公众号:前端印象
- 不定时有送书活动,记得关注~
- 关注后回复对应文字领取:【面试题】、【前端必看电子书】、【数据结构与算法完整代码】、【前端技术交流群】
异步编程——Ajax
一、什么是Ajax
Ajax(Asynchronous JavaScript And XML)是2005年新出现的技术,它的出现是为了解决这样一个场景:整个页面中,只有一小部分的数据需要进行更新,按照传统的前后端交互,我们需要向服务器请求该网页的所有数据,然后再在客户端重新渲染,这无疑是非常低效的操作。因此,Ajax就可以做到只向服务器请求我们想要的那一小部分数据,而不用请求全部数据,进而在刷新整个页面的前提下更新那部分的数据。
举个例子,我们去饭店吃饭,然后点了一桌子菜,后来发现其中有一道菜太咸了,因此我们只需要让服务员端回去给厨师重新做这一道菜再拿回来就行了。
在这个例子中的人、物对比Ajax的关系如下表:
吃饭事件 | 数据更新 |
---|---|
我们 | 客户端 |
菜品 | 页面所有的数据 |
服务员 | ajax对象 |
厨师 | 服务器 |
当我们发现有一道菜太咸了,不需要让厨师把所有的菜重新做一遍,只要让服务员拿这一道菜回去给厨师重做这一操作就相当于让ajax对象向后端请求那一小部分数据再拿回来更新页面而无需刷新整个页面。
二、Ajax的优缺点
了解了Ajax的作用和定义,我们再来看看它的优缺点
(1)优点
- 浏览器默认支持(一般浏览器都是支持JavaScript的)
- 提高用户体验(不需要刷新整个页面,而只需要局部刷新)
- 提高页面的性能(只需要请求部分数据,所以数据量就明显下降了)
(2)缺点
- 破坏了浏览器的前进和后退功能(Ajax不会改变网页URL,因此不会在浏览器记录前后页面)
- 对搜索引擎的支持较弱(搜索引擎无法监测到JS引起的数据变化)
三、Ajax的使用
Ajax的基本流程:创建XHR对象 => 发送数据 => 接收数据
(1)状态码
既然Ajax涉及到前后端的数据交互,那么我们就先来简单的看一下几种类型的状态码,如下表:
状态码 | 含义 |
---|---|
100 ~ 199 | 连接继续 |
200 ~ 299 | 各种成功的请求 |
300 ~ 399 | 重定向 |
400 ~ 499 | 客户端错误 |
500 ~ 599 | 服务端错误 |
(2)xhr的基本使用
在使用xhr之前,我们要创建一个xhr的实例对象
let xhr = new XMLHttpRequest()
- 1
然后再调用xhr对象上的 open()
方法,表示创建一个请求。
open()
方法接收三个参数:
- 第一个参数: 请求的类型(例如get 、post)
- 第二个参数: 请求的URL
- 第三个参数: 是否异步发送请求(默认为true)
// 创建了一个Ajax请求
xhr.open('get', 'example.php', 'true')
- 1
- 2
光调用了 open()
方法还不够,它只是创建了一个请求,但还没有发送请求,因此我们还要调用xhr对象上的另一个方法,即 send()
方法,表示将请求发送给目标URL
send()
方法接收一个参数:
- 第一个参数: 作为请求主体发送的数据(例如post请求携带的数据)
// 我们上面创建的是get请求,因此send()方法无需传参
xhr.send()
- 1
- 2
请求发送出去后,客户端需要接收服务器响应回来的数据,xhr对象中有一些属性,它们存储着服务端返回来的一些数据信息,如下表所示
属性名 | 含义 |
---|---|
responseText | 服务端返回的文本信息 |
responseXML | 服务端返回的XML DOM文档 |
status | HTTP状态码 |
statusText | HTTP状态码说明 |
readyState | xhr对象的请求响应阶段 |
既然我们要获取服务端返回的数据,我们就要知道服务端是何时返回数据的,这就可以通过上面表格中的 readyState
属性来判断了
readyState
属性一共有5个值,分别表示不同的请求响应阶段:
- 0: 还未创建请求,即未调用
open()
方法 - 1: 已调用
open()
方法,但未发送send()
方法 - 2: 已调用
send()
方法,但未接收到响应 - 3: 已接收到部分响应
- 4: 已接收到全部的响应
同时,xhr对象可以绑定一个 readystatechange
事件,每当 readyState
属性发生改变,都会触发该事件,因此,该事件在一次请求中会被多次触发
xhr.onreadystatechange = function() {
console.log('readyState属性发生改变了')
}
- 1
- 2
- 3
所以,我们可以在 readystatechange
事件中判断一下 readyState
属性是否为 4
,即是否已经接收所有的响应,然后还可以再继续判断一下 status
属性,看看状态码是否为 200
,当上述都成立了,我们再去 responseText
属性 或 responseXML
属性中获取响应数据
xhr.onreadystatechange = function() {
// 判断是否已接收所有响应
if(xhr.readyState === 4) {
// 判断状态码是否为200
if(xhr.status === 200) {
console.log(xhr.responseText)
}
}
}
然后我们上面也说过,send()
方法接收的一个参数是请求主体发送的数据,所以我们的post请求要发送的数据就要作为该方法的参数,代码如下:
xhr.send('query=4&em=0')
- 1
那我们来看一次完整的post请求是怎么样的吧,代码如下:
let xhr = new XMLHttpRequest()
xhr.open('post', 'example.php')
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
xhr.send('query=4&em=0')
xhr.onreadystatechange = function() {
if(xhr.readyState === 4) {
if(xhr.status === 200){
console.log(xhr.responseText);
}
}
}
}, ‘json’)
其调用的是一个综合的方法,传入的参数是一个对象,对象中传入多个参数。这段代码是发送了一个 get
请求,地址为 example.php
,携带的参数有 query
值为 4
、em
值为 0
,所接收返回数据的类型为 json
,请求为异步请求
特别的是,该方法的回调函数是通过 promise
实现的,即该方法返回一个 promise
对象,在 then
函数中处理请求成功的情况,在 catch
函数中处理请求失败的情况
若没有了解过 promise
的小伙伴建议先花几分钟了解一下,因为这是异步编程最常用的一个语法,下面放上文章链接——深入了解Promise对象,写出优雅的回调代码,告别回调地狱
接下来我们就针对上述给出的例子,逐个封装
(2)封装准备工作
因为 XMLHttpRequest
对象有一定的兼容性,因此我们在封装ajax方法之前可以先封装一个方法用来动态创建一个兼容性稍微好点的XHR对象(其中主要是兼容IE5和IE6)
我们都知道JQuery都是将方法封装在一个名为 $
的对象中的,我们也这么做
let $ = {
createXHR: function() {
// 若浏览器支持,则创建XMLHttpRequest对象
if(window.XMLHttpRequest) {
return new XMLHttpRequest()
}
// 若不支持,则创建ActiveXobject对象
else {
return new ActiveXObject()
}
}
}
(4)封装$.post方法
JQuery的 post
方法传入的参数跟 get
方法一样,只不过其内部的实现有略微的区别,就是携带参数的发送不一样,所以直接来看代码吧
let $ = {
// 动态生成XHR对象的方法
createXHR: function() {
if(window.XMLHttpRequest) {
return new XMLHttpRequest()
} else {
return new ActiveXObject()
}
},
post: function(url, data, callback, dataType) {
// 避免dataType大小写的问题
let dataType = dataType.toLowerCase()
// 调用我们封装的方法动态生成XHR对象
let xhr = this.createXHR()
五、Ajax的约束
默认情况下,Ajax一般只能向同源的域发送请求,这是受到了浏览器的同源策略的限制,关于同源策略,你们可以去看一下我以前写过的一篇博客,里面写了同源策略的定义以及解决方案——前端人员都懂的浏览器的同源策略,以及如何进行不同源间的相互访问
了解过同源策略以后,我们来看看如何让Ajax不受同源策略的限制而成功发送请求。CORS(跨域资源共享)要求我们在发送请求时自定义一个HTTP头部与服务器进行沟通,我们只需要设置一个名为 Origin
的头部,值为当前页面的源信息(协议、域名、端口),例如 Origin : http://example.com
;然后服务器需要设置一个名为 Access-Control-Allow-Origin
的响应头部,其值为允许跨域访问的源信息,若服务器设置的 Access-Control-Allow-Origin
与我们设置的 Origin
相同,则表示服务器允许我们跨域请求其资源,或者服务器可以将 Access-Control-Allow-Origin
值设为 *
,此时表示允许任何域向其发送请求并且不受同源策略的限制。
现在的大部分浏览器几乎都支持了在发送Ajax请求后,自动向请求头部添加当前的源信息
六、结束语
建议你们好好了解JS的Ajax的使用,这样在面试中问起来你还能说出个一二三,并且有时候面试官还会直接让你亲手写一个简单的Ajax请求呢,而不会让你使用JQuery的。看了本文,想必面试官如果让你当场封装一个类似JQuery的Ajax请求,你也不会手足无措呢
欢迎关注公众号:前端印象 , 不定时更新前端面试题,与我一起学习前端,早日斩获大厂Offer