跳到主要内容

AJAX 原生封装

前后端混编时代

在 AJAX 出现之前,我们通常采用前后端混编的方式进行 Web 开发。所谓混编,就是将前端页面和后端逻辑写在一起,文件后缀名一般是后端语言的后缀,比如.php

混编虽然简单方便,但也存在一些问题:

每次请求都会刷新整个页面,用户体验不好 前后端代码耦合在一起,不利于开发和维护

AJAX 的诞生

AJAX 的出现,改变了 Web 开发的模式。有了 AJAX,我们就可以在不刷新页面的情况下,异步地向服务器发送请求,获取数据,然后局部更新页面。这极大地改善了用户体验。

AJAX 的诞生和发展历程如下:

时间事件描述
1999IE5.0允许**JS**脚本向服务器单独发起**HTTP**请求的新功能
2004Gmail异步更新邮件
2005Google Map异步更新地图服务
2005AJAX被大厂公认命名
2006W3C发布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);
},
});