何为 ajax?
ajax 全名为 Asynchronous JavaScript and XML = 异步 JS + XML
ajax 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术(通过在后台发送异步 HTTP 请求并接收响应)。相比于传统网页如果需要更新页面,就必须重新刷新页面,ajax技术使网页变得更加动态和响应迅速,极大地提升了用户的交互体验。
异步请求
运行在不堵塞主线程的同时发送请求,页面的加载和用户的操作不在同一个线程上,互不打扰。这样用户可以继续浏览或与页面互动,而不会被全页刷新打断。
注:如果不理解异步的话可以翻看我之前的文章 掌握异步编程精髓:从回调地狱到promise再到async/await 的优雅进化 - 掘金
ajax 的工作流程
- 用户触发事件(例如点击按钮)。
- 发送请求 :JavaScript 创建一个
XMLHttpRequest
对象(或使用现代的fetch
API),并向服务器发送请求。 - 服务器处理请求:服务器接收并处理请求,然后返回响应(JSON、XML、HTML等)。
- ajax响应处理:JavaScript 接收响应并根据需要更新页面的部分内容。
ajax 操作实例
不妨假设现在需要从GitHub API异步获取组织成员信息,并将其显示在网页上,并且要求使用异步获取数据。
传统基于 XMLHttpRequest 对象
1. 创建 XMLHttpRequest 对象:
javascript
const xhr = new XMLHttpRequest(); // 实例化一个 xhr 请求对象
2. 初始化请求:
javascript
xhr.open('GET', 'URL', true); // true 同意异步请求
此处open
方法用于初始化请求,其接收三个参数,格式为: xhr.open( 配置请求方式,请求地址,是否异步 )
3. 设置回调函数✨:
javascript
xhr.onreadystatechange = function() {
if (xhr.readyState !== 4) return;
if (xhr.status === 200 || xhr.status === 304) {
const data = JSON.parse(xhr.responseText)
resolve(data)
} else {
reject(new Error(xhr.responseText))
}
}
分析
onreadystatechange
事件处理程序会在XMLHttpRequest
对象的readyState
发生变化时被调用。readyState
属性表示请求的状态:
yaml
0 : 请求未初始化。
1 : 请求已建立,但尚未发送。
2 : 请求已发送,但尚未收到响应。
3 : 请求正在处理中,部分数据已经接收。
4 : 请求已完成,且响应已就绪。
-
status
属性表示HTTP状态码其等于200
或304
时,表示请求成功。 -
使用
JSON.parse
将响应文本转换为JavaScript对象。
resolve函数
用于将Promise的状态从
Pending
转变为Fulfilled
,并传递结果数据给后续的处理程序。reject函数
用于将Promise的状态从
Pending
转变为Rejected
,并传递错误信息给后续的处理程序。
4.发送请求:
javascript
xhr.send();
代码演示:
html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<ul id="memberList">
</ul>
<script>
const oUL = document.getElementById('memberList');
const xhr = new XMLHttpRequest();
xhr.open('GET', 'URL', true);
xhr.onreadystatechange = function() {
if (xhr.readyState !== 4) return;
if (xhr.status === 200 || xhr.status === 304) {
const data = JSON.parse(xhr.responseText)
resolve(data)
} else {
reject(new Error(xhr.responseText))
}
}
xhr.send()
</script>
</body>
</html>
现代fetch
API 基于 Promise 对象
1. 发起fetch
请求:
JavaScript
fetch('URL')
.then(res => res.json()) // 将返还的二进制代码转换为json对象
.then(data => {
// 处理数据
})
.catch(error => console.error('Error:', error)); // 捕获错误
分析
- 使用
fetch
API发起一个GET请求到指定的URL。 fetch
返回一个 Promise,该 Promise 在请求成功时解析为响应对象。
2. 数据处理:
javascript
oUL.innerHTML = data.map(member => `
<li>
<span>${member.login}</span>
</li>
`).join(''); // 将json对象赋值给data变量
分析
data.map(member => { ... })
:遍历data
数组中的每个成员对象,并生成相应的HTML字符串。.join('')
:将数组中的所有 HTML 字符串用''
连接成一个完整的字符串。- 最后将生成的 HTML 字符串赋值给
oUL.innerHTML
,从而动态更新页面内容。
代码演示
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ajax</title>
</head>
<body>
<ul id="memberList">
</ul>
<script>
const oUL = document.getElementById('memberList');
fetch('URL')
.then(res => res.json())
.then(data => {
oUL.innerHTML = data.map(member => `
<li>
<span>${member.login}</span>
</li>
`).join('')
})
</script>
</body>
</html>
手写Ajax
在手写ajax之前,需要知道ajax请求的执行流程,即:URL -> http请求(200+4) -> 异步耗时任务 -> 执行流程(DOM) -> promise,知道流程后就可以一步步拆解代码了
步骤详解:
javascript
// 6.创建getJSON函数获取目标URL
const getJSON = function(url) {
// 5.Promise封装
return new Promise((resolve, reject) => {
// 1.创建 XMLHttpRequest 对象
const xhr = XMLHttpRequest
? new XMLHttpRequest()
: new ActiveXObject("Microsoft.XMLHTTP");
// 2. 规定 请求的类型、URL、是否异步
xhr.open("GET", url, true);
// 3. 设置状态监听函数
xhr.onreadystatechange = function() {
if (xhr.readyState !== 4) return;
if (xhr.status === 200 || xhr.status === 304) {
resolve(xhr.responseText)
} else {
reject(new Error(xhr.responseText))
}
}
// 4.发送请求到服务器
xhr.send();
})
}
1. 创建 XMLHttpRequest 对象
javascript
const xhr = XMLHttpRequest
? new XMLHttpRequest()
: new ActiveXObject("Microsoft.XMLHTTP");
由于在一些旧版本的 IE 浏览器(如 IE6 和 IE7)中,不支持 XMLHttpRequest
,而是使用 ActiveXObject
来创建类似的功能对象。
所以这里通过三元运算符来选择创建的实例:
- 支持
XMLHttpRequest
:创建并返回一个新的XMLHttpRequest
实例。 - 不支持
XMLHttpRequest
:创建并返回一个新的ActiveXObject
实例,类型为"Microsoft.XMLHTTP"
。(微软提供的一个用于发送 HTTP 请求的对象)
亮点:
-
浏览器兼容性:
- 确保代码在大多数现代浏览器以及一些旧版本的 IE 浏览器中都能正常运行。
- 利用三元运算符的简洁性,使得代码更加紧凑和易读。
-
条件判断:
- 使用
XMLHttpRequest
是否存在作为判断条件,是一种常见的浏览器嗅探(browser sniffing)技术。 - 这种方式避免了直接检测用户代理字符串(User-Agent),从而减少了误判的可能性。
- 使用
2 and 4. 发送请求到服务器
javascript
xhr.open("GET",'url',true);
xhr.send();
3. 设置状态监听函数
javascript
xhr.onreadystatechange = function() {
if (xhr.readyState !== 4) return;
if (xhr.status === 200 || xhr.status === 304) {
resolve(xhr.responseText)
} else {
reject(new Error(xhr.responseText))
}
}
每当 readyState
改变时,就会触发 onreadystatechange
事件,并且根据http响应码(xhr.status
)来确定请求是否成功。
而当readyState
为4,并且xhr.status
为200或304时就代表服务器响应就绪,接下来就可以进行任意操作了。并且通过xhr.responseText
就可以访问数据了。
xhr.responseText - 服务器以文本字符的形式返回
5. Promise封装
javascript
new Promise((resolve, reject) => {
const xhr = XMLHttpRequest
? new XMLHttpRequest()
: new ActiveXObject("Microsoft.XMLHTTP");
xhr.open("GET", url, true);
xhr.onreadystatechange = function() {
if (xhr.readyState !== 4) return;
if (xhr.status === 200 || xhr.status === 304) {
resolve(xhr.responseText)
} else {
reject(new Error(xhr.responseText))
}
}
xhr.send();
})
这里插入一个小知识点方便各位理解Promise类
Promise() 构造函数
语法: new Promise(executor)
--> new Promise((resolve,reject) => {})
executor
是在构造函数中的function,并且其接收两个函数resolvefunc
和rejectfunc
,这俩个函数控制着Promise
的状态。
- resolve : 当异步操作成功完成时调用,将
Promise
的状态从"pending"变为"fulfilled",并传递结果,后执行.then()
。 - reject : 当异步操作失败时调用,将
Promise
的状态从"pending"变为"rejected",并传递错误信息,后执行.catch()
。
注:状态只会从 pending 到 fulfilled 或 rejected 状态,并且状态一旦确定就不再改变了。
测试:
javascript
getJSON('URL')
.then(data => {
console.log(data)
})