AJAX 原生封装
前后端混编时代
在 AJAX 出现之前,我们通常采用前后端混编的方式进行 Web 开发。所谓混编,就是将前端页面和后端逻辑写在一起,文件后缀名一般是后端语言的后缀,比如.php
。
混编虽然简单方便,但也存在一些问题:
每次请求都会刷新整个页面,用户体验不好 前后端代码耦合在一起,不利于开发和维护
AJAX 的诞生
AJAX 的出现,改变了 Web 开发的模式。有了 AJAX,我们就可以在不刷新页面的情况下,异步地向服务器发送请求,获取数据,然后局部更新页面。这极大地改善了用户体验。
AJAX 的诞生和发展历程如下:
时间 | 事件 | 描述 |
---|---|---|
1999 | IE5.0 | 允许**JS** 脚本向服务器单独发起**HTTP** 请求的新功能 |
2004 | Gmail | 异步更新邮件 |
2005 | Google Map | 异步更新地图服务 |
2005 | AJAX 被大厂公认命名 | |
2006 | W3C 发布AJAX 国际标准 |
可以看到,AJAX 的概念最早由微软提出,后来在 Google 等公司的推动下迅速发展,成为 Web 开发的主流技术。
同步请求 vs 异步请求
在理解 AJAX 之前,我们需要先搞清楚同步请求和异步请求的区别。
同步请求的特点是:
请求发出后,需要等待服务器响应 在此期间,浏览器不能做其他事情 页面会被完全刷新
而异步请求的特点是:
请求发出后,不需要等待服务器响应,可以继续做其他事情
获得响应后,可以局部刷新页面
显然,异步请求的用户体验要好得多。AJAX 就是实现异步请求的利器。
XMLHttpRequest 对象
要使用 AJAX 发送异步请求,关键是要使用XMLHttpRequest
对象。它是浏览器内置的一个构造函数,用于发起 HTTP 请求。
XMLHttpRequest
的基本用法如下:
var xhr = new XMLHttpRequest();
注意,在 IE5/IE6 中,需要使用ActiveXObject
来创建XMLHttpRequest
对象:
var xhr = new ActiveXObject('Microsoft.XMLHTTP');
为了兼容不同浏览器,我们可以封装一个函数:
function createXHR() {
if (window.XMLHttpRequest) {
return new XMLHttpRequest();
} else {
return new ActiveXObject('Microsoft.XMLHTTP');
}
}
XMLHttpRequest 的状态
XMLHttpRequest
对象在请求的过程中,会经历不同的状态。我们可以通过readyState
属性来获取当前状态:
0
请求未初始化
1
服务器连接已建立
2
请求已接收
3
请求处理中
4
请求已完成,且响应已就绪
另外,我们还可以通过status
属性获取服务器响应的状态码,比如200
表示成功,404
表示未找到资源等。
在readyState
变化时,会触发onreadystatechange
事件。我们可以监听该事件,根据不同状态执行不同操作:
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// 请求成功,获取响应数据
console.log(xhr.responseText);
} else {
// 请求失败,处理错误
}
}
};
封装 AJAX
了解了XMLHttpRequest
的基本用法后,我们就可以尝试封装一个简单的 AJAX 函数了:
function ajax(options) {
var xhr = createXHR();
// 合并默认参数
var opts = Object.assign(
{
url: '',
type: 'GET',
data: null,
success: function () {},
error: function () {},
complete: function () {},
},
options
);
// 监听状态变化
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
opts.success(JSON.parse(xhr.responseText));
} else {
opts.error();
}
opts.complete();
}
};
// 格式化请求参数
var data = formatData(opts.data);
// 发起请求
xhr.open(opts.type, opts.url, true);
if (opts.type === 'GET') {
xhr.send();
} else {
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.send(data);
}
}
// 格式化请求参数
function formatData(data) {
var arr = [];
for (var key in data) {
arr.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]));
}
return arr.join('&');
}
上面的ajax
函数接收一个配置对象,可以设置请求的url
、类型、参数、成功/失败回调等。
在内部,先创建一个XMLHttpRequest
对象,然后:
监听onreadystatechange
事件,根据状态调用成功/失败/完成的回调
格式化请求参数
根据请求类型,调用xhr.send()
方法发送请求
这样,我们就可以方便地使用封装好的ajax
函数来发送异步请求了:
ajax({
url: '/api/getData',
type: 'POST',
data: { id: 123 },
success: function (res) {
console.log(res);
},
});