Ajax是什么
AJAX即“Asynchronous JavaScript and XML”(异步的JavaScript与XML技术),指的是一套综合了多项技术的浏览器端网页开发技术,包含了HTML、CSS、JavaScript、DOM、XML等技术。Aiax 只是一个哥们“发明”的缩写,这个新术语用来描述一种使用现有技术集合的一个名称。多项技术中最重要的是 XMLHttpRequest 对象,稍后会介绍到它。
如果不使用 Ajax,仔细观察一个Form的提交,你就会发现,一旦用户点击“Submit”按钮,表单开始提交,浏览器就会刷新页面,然后会跳到新页面里告诉你操作是成功了还是失败了。如果失败了,还要返回表单填写页,有些信息会丢失,需要重新填写,这对用户体验极其不友好。
这是Web的运作原理:一次HTTP请求对应一个页面。
如果要让用户留在当前页面中,同时发出新的HTTP请求,就必须用JavaScript发送这个新请求,接收到数据后,再用JavaScript更新页面,这样一来,用户就感觉自己仍然停留在当前页面,数据却可以不断地更新。
也就是说,当使用了 Ajax 后,可以在不重新刷新页面的情况下与服务器通信,交换数据,更新页面, 这样能够快速地将数据更新呈现在用户界面上,这使得程序能够更快地回应用户的操作。
可以利用 Ajax 的特性做如下事情:
- 在不重新加载页面的情况下发送请求给服务器
- 接受并使用从服务器响应的数据。
交换的数据格式
使用 AJAX 技术中的 XMLHttpRequest 对象与服务器通信,交换数据。数据的格式可以使用JSON,XML,HTML和文本等多种格式发送和接收。尽管X在Ajax中代表XML, 但由于JSON的许多优势,更加轻量以及是Javascript的一部分,目前JSON的使用比XML更加普遍。
关于JSON
JSON(JavaScript Object Notation) 是一种轻级的数据交换格式。JSON实际上是JavaScript的一个子集。但是和JavaScript的语法稍微有些不同,有属于JSON自己的语法。
JSON构建于两种形式:
- 无序的“‘名称/值’对”集合
一个对象以“{”(左括号)开始,“}”(右括号)结束。每个“名称”后跟一个“:”(冒号);“‘名称/值’ 对”之间使用“,”(逗号)分隔。 - 值的有序列表
一个数组以“[”(左中括号)开始,“]”(右中括号)结束。值之间使用“,”(逗号)分隔。
在JSON中值支持以下几种数据类型:
- number:和JavaScript的number完全一致,在JSON中数字不能以0开头。
- boolean:JavaScript的true或false;
- string:JavaScript的string;
- null:JavaScript的null;
- array:JavaScript的Array表示方式——[];在JSON中结尾不能有逗号。
- object:JavaScript的{ ... }表示方式。在JSON中结尾不能有逗号,key值必须加上双引号。
在JavaScript中,可以直接使用JSON,JavaScript内置了JSON的解析。
JSON 对象
JSON对象定义在全局,该对象包含了两个方法,除了这两个方法, JSON这个对象本身并没有其他作用,也不能被调用或者作为构造函数调用。
JSON.stringify()
将 JavaScript 中的对象或数组序列化成JSON字符串。简单来说 JSON 是 JavaScript 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。
序列化将对象的状态信息转换为可以存储或传输的形式的过程。
例如在 JavaScript 中定义的对象:
let obj = {a:1,b:2}
此对象存在于内存中,并不能将期结构存储在cookie或localStorage或传递给后端。而此时就需要调用此方法序列换为一个 JSON 字符串。
console.log(JSON.stringify(obj)); // {"a":1,"b":2}
JSON.parse()
将 JSON 字符串反序列化成 JavaScript 中的对象或数组。JSON 字符串本身只是一个字符串,不能通过属性名的方式获取对应的值。要转换为对象就可以使用 key 来取值。
反序列化将可以存储或传输的形式转换为对象的过程。
例如从后端拿到一个 JSON 字符串 :
let objStr = '{"a":1,"b":2}'
此时不能使用 objStr.a 取到数值1,因为 objStr 本身只是一个字符串值,并不是对象。
需要把JSON 字符串转成可用的对象:
console.log(JSON.parse(objStr)); // {"a":1,"b":2}
异步
Ajax 中的Asynchronous 是异步的意思,结合 Ajax 可以和服务器进行通信,可以说Ajax是用JavaScript执行异步的网络请求。
所谓的异步就是,一个异步过程调用发出后,调用者不会立刻得到结果。而是在 调用 发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。
其中DOM事件,定时器就是典型的异步操作。拿定时器举例,当调用 setTimeout 函数时候,就发起了一个异步操作,此时不会立马得到反馈,而到了设置的时间,会调用传入的回调函数,一旦回调函数执行就得到通知说明异步完成了。
setTimeout(function(){
console.log('执行此回调函数,异步完成得到通知,该干嘛干嘛!!!');
}, 1000)
与之对应的还有一个同步的概念,所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了。由调用者主动等待这个调用的结果。
比如拿一个 JavaScript 中函数调用举例:
var arr = [1,2,3,4,5,6,7,8];
arr.map((item) => {
return item * 2
})
arr.forEach((item) => {
return item * 2
})
上述代码中只有 map 指向之后,得到了结果,才能继续调用 forEach, 这是一个同步调用的过程。
在使用 Ajax 时候,发出的是一个异步请求,要通过调用函数获得响应。
分解Ajax中的知识点
使用 JavaScript 创建一个请求对象实例,调用该实例下的方法,设置好请求的URL地址和请求数据,发送异步请求。发送后等待服务端响应,响应是以触发事件来通知,随后通过请求对象实例拿到HTTP状态以及响应的内容。
完成一次请求,代码示意如下所示
let xhr = new XMLHttpRequest;
console.log(xhr.readyState); // 0 UNSENT 创建实例对象,尚未调用open();
xhr.open('GET','http://kuapi.wykiss.cn/api?json=true',true);
console.log(xhr.readyState); // 1 OPENED open()方法已成功调用。
// 当readyState状态发生变化时,触发此事件
xhr.onreadystatechange = function () {
console.log(xhr.readyState);
if(xhr.readyState === 2){ // 2 HEADERS_RECEIVED 可以获取到响应头信息
console.log('响应头信息为:',xhr.getAllResponseHeaders())
}else if(xhr.readyState === 3){ // 3 LOADING 正在接收部分响应内容
console.log('接收的部分内容是:',xhr.response)
}else if(xhr.readyState === 4) { // 4 DONE 请求操作已经完成,响应的内容全部接受完成
console.log('接收全部内容是:',xhr.response)
}
}
// 请求操作完成 触发的事件
xhr.onload = function () {
console.log('请求操作完成,触发此事件')
console.log('可以直接获取响应的全部内容',xhr.response)
}
xhr.send();
咋眼一看,内容还挺多,分解每一个知识点如下。
XMLHttpRequest 对象
XMLHttpRequest 是规范制定的API,已经被现代浏览器广泛使用,它为客户端提供了在客户端和服务器之间传输数据的功能,是Ajax技术的核心所在。
全局会提供一个 XMLHttpRequest 构造函数来初始化一个请求实例对象。
var xhr = new XMLHttpRequest();
此对象上会有多个属性和方法。
readyState 属性
只读属性,xhr.readyState 记录了请求实例对象运行过程中所处的状态,使用数字来表示。以下是每个数字代表的含义:
值 | 状态 | 描述 |
---|---|---|
0 | UNSENT | 请求对象已创建,尚未调用 open()方法 |
1 | OPENED | open()方法已成功调用 |
2 | HEADERS_RECEIVED | send() 方法已调用,可以获取到响应头信息 |
3 | LOADING | 正在接收部分响应内容 |
4 | DONE | 请求操作已经完成,响应的内容全部接受完成 |
response 和responseText 属性
两个都是只读属性,存的是服务器的响应内容。 responseText表示服务器响应内容的文本形式。
responseType 属性
可读可写属性,xhr.responseType 表示响应的类型, 缺省为空字符串, 可取 "arraybuffer" , "blob" , "document" , "json" , and "text" 共五种类型。
当将responseType设置为一个特定的类型时,你需要确保服务器所返回的类型和你所设置的返回值类型是兼容的。那么如果两者类型不兼容,服务器返回的数据变成了null,即使服务器返回了数据。还有一个要注意的是,给一个同步请求设置responseType会抛出一个InvalidAccessError 的异常。
responseURL 属性
xhr.responseURL 返回ajax请求最终的URL, 如果请求中存在重定向, 那么responseURL表示重定向之后的URL。
status 属性
只读属性。xhr.status存的是数字状态码,是标准的HTTML状态码。在请求完成前,status的值为0。如果请求出错,浏览器返回的 status 也为0。如果服务器响应中没有明确指定status码, status码将会默认为200。
statusText 属性
只读属性。xhr.status存的是服务器返回的状态短语。这个属性包含了返回状态对应的文本信息,例如"OK"或是"Not Found"。
open() 方法
xhr.open() 方法初始化一个请求。
语法:
xhr.open(method, url)
xhr.open(method, url, async)
- method 要使用的HTTP方法,比如 「GET」、「POST」、「PUT」、「DELETE」等。常用的是「GET」、「POST」请求方式。其他的方法后端需要特别的支持。
接下来讨论的是在浏览器应用层面中GET和POST发送数据的不同。
- GET产生的URL地址可以被Bookmark,而POST不可以。
- GET请求只能进行url编码,而POST支持多种编码方式。
- GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
- GET请求在URL中传送的参数是有长度限制的,而POST么有。
- GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
- GET参数通过URL传递,POST放在Request body中。
- url 发送请求的URL地址。如果发送的是 get 请求要把数据写在地址栏的后面发送给后端。例如:
http://kuapi.wykiss.cn/api?js...
-
async 可选参数。默认为true,表示执行是不是执行异步操作。true,为异步,false,为同步。当设置false时,浏览器会出现一个警告。
- 异步请求发出后,调用者不会立刻得到结果。而是在 调用 发出后,被调用者通过触发事件,调用事件处理回调函数。在没有得到后端返回的结果之前,异步操作之后的代码会继续执行。
// Ajax 发出异步请求 // ..... 代码省略 console.log('没得到结果,我先执行');
- 同步请求发出后,在没有得到结果之前,该调用就不返回。这就意味着,后续的代码不能被执行,只有等到同步调用结束后得到了结果,才能继续执行代码。
// Ajax 发出同步请求 // ..... 代码省略 console.log('只有同步操作完成后,我才能执行');
send() 方法
xhr.send() 方法用于发送 HTTP 请求。如果是异步请求(默认为异步请求),则此方法会在请求发送后立即返回,接着继续执行send后面的代码;如果是同步请求,则此方法直到服务端响应结束后全部拿到响应的数据后才会返回。
xhr.send() 方法接受一个可选的参数,其作为请求主体,发送 post 时会用到;如果请求方法是 GET,则应将请求主体设置为 null。
注意:请求方法为 post 时,要在请求头(headers)中的 Content-Type 设置消息主体编码方式,这样服务端通常是根据请求头(headers)中的 Content-Type 字段来获知请求中的消息主体是用何种方式编码,再对主体进行解析。
- application/x-www-form-urlencoded
Content-Type 被指定为 application/x-www-form-urlencoded;提交的数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码。大部分服务端语言都对这种方式有很好的支持。例如 PHP 中,$_ POST[' json '] 可以获取到 true 的值,$_POST['country'] 可以得到 中国 值。
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send('json=true&country=中国');
-
关于URL编码
- URL编码是一种浏览器用来打包表单输入的格式,浏览器从表单中获取所有的name和其对应的value,将他们以name/value编码方式作为URL的一部分或者分离的发送到服务器上。在 ajax 中要手动设置 Content-Type 为 application/x-www-form-urlencoded。
- URL编码规则:每对name/value由&分开,每对来自表单的name/value用=分开。如果用户没有输入值的那个name依旧会出现不过就是没有值。URL编码是在字符ASCII码的十六进制数的前面加上%。例如:中国 被转成了 %E4%B8%AD%E5%9B%BD 。
onload 事件
在ajax请求操作完成后触发, 触发时机在 readyState==4 状态之后,这时候返回的内容已全部接受。
xhr.onload = function(){
var s = xhr.status;
if((s >= 200 && s < 300) || s == 304){
var resp = xhr.responseText;
//TODO ...
}
}
onreadystatechange 事件
在readystate记录的状态改变时触发。onreadystatechange 方法会被触发4次。通常在事件处理函数中判断 readystate 为4的情况下,才算全部接受到内容。
xhr.onreadystatechange = function(e){
if(xhr.readyState==4){
var s = xhr.status;
if((s >= 200 && s < 300) || s == 304){
var resp = xhr.responseText;
//TODO ...
}
}
}
以上是对Ajax知识点的总结,如有问题,欢迎指正!
扩展阅读:
- readyState状态描述
https://xhr.spec.whatwg.org/#states
- 关于URL编码
http://www.ruanyifeng.com/blog/2010/02/url_encoding.html
- 四种常见的 POST 提交数据方式:
https://imququ.com/post/four-ways-to-post-data-in-http.html
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。