ajax 单独用英语念就是阿贾克斯, 而阿贾克斯是一个足球俱乐部, 叫起来也郎朗上口, 所以中国的程序员都称 ajax 为阿贾克斯, 它是一种前后端交互的异步优化技术, 能达到不刷新网页就可以往后端传数据实现交互, 大大提高了用户体验, 这种技术的概念是由一位美国人 杰西·詹姆士·贾瑞特 提出来的, 他原来是一名设计师, 然后为了提高用户体验而想出来的 ajax 构想, 详见 维基百科
XMLHttpRequest
这是 js 内置的 ajax 对象, 他构造出来的对象就可以实现一个 ajax
const request = new XMLHttpRequest();
request.open('GET', '/a/b/c?name=ff', true);
request.onreadystatechange = function() {
if (request.readyState === 4 && request.status === 200) {
console.log(request.responseText);
}
};
request.send();
resquest 是 XMLHttpRequest 的实例, 他有很多种方法
- open: 初始化一个请求, 参数包括 请求方法, 请求路径, 是否异步, 用于认证的用户, 用于认证的密码
- onreadystatechange:当状态发生变化时, 会触发这个事件, 主要用来判断请求是否成功
- readyState: 代表请求的状态码, 一共有 5 种
- 0: 代理被创建, 但是未被调用 open 方法
- 1: open 方法被调用
- 2: send 方法已经被调用, 响应头和响应状态已经获得
- 3: 下载中响应体中
- 4: 下载操作完成, 表示整个请求已完成
- status: 响应中的数字状态码, 也就是我们常说的 HTTP 状态码
- send: 发送请求
这样一个简单的 ajax 请求就已完成
进阶 Ajax
上一节实现的是 GET 请求, 那么众所周知请求除了 GET 还分很多种, POST, PUT, DELETE, OPTIONS, 等等, 还有其他请求有的会带上请求体, 那么上面的方法已经不能满足所需, 所以我们实现一个支持多种方法的 ajax
function ajax(options) {
let method = options.method || 'GET';
let params = options.params;
let data = options.data;
let url = options.url + (params ? `?${Object.keys(params).map((key) => key + '=' + params[key]) .join('&')}` : '')
let isAsync = options.async === false ? false : true;
let success = options.success;
let fail = options.fail
let headers = options.headers;
let xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
success && success(xhr.responseText);
}
};
xhr.onerror = (err) => {
fail && fail(err)
};
xhr.open(method, url, isAsync);
if (headers) {
Object.keys(headers).forEach((key) =>
xhr.setRequestHeader(key, headers[key])
);
}
method === 'GET' ? xhr.send() : xhr.send(data);
}
我们实现一个封装方法, 方法接收一个对象, 然后把根据对象里的数据来判断何种请求以及所带的数据
options 里的属性:
- method: 请求方法
- params: 请求参数
- url: 请求路径
- async: 是否异步
- success: 成功回调
- fail: 失败回调
- headers: 设置请求头
- data: 请求体
然后根据这些属性判断是否存在做进一步的操作, 我在代码里做了兼容 IE 的操作, ActiveXObject 是 IE 里的 ajax 构造函数, 这也是面试经常问的一个考点
里面有一些 api 我没有介绍, 这时候需要你去 mdn 上看文档, 学会自己看文档是一个很重要的能力
等你把这个封装函数消化透你就会发现这其实就是简单封装了一下 XMLHttpRequest 生成对象, 然后做的一系列操作, 没有什么难点
就像现在前端经常用的 ajax 库 axios 一样, 它的核心原理也就是这样, 不同的是它做了很多边缘化的处理和很好的错误处理, 而且还加上了 Promise, 使得异步调用很方便, 而且代码可读性很好, 接下来我们就让这个函数返回一个 Promise, 我们也可以实现链式调用了
function ajax(options) {
return new Promise((resolve, reject) => {
let method = options.method || 'GET';
let params = options.params;
let data = options.data;
let url =
options.url +
(params
? `?${Object.keys(params)
.map((key) => key + '=' + params[key])
.join('&')}`
: '');
let isAsync = options.async === false ? false : true;
let success = options.success;
let fail = options.fail;
let headers = options.headers;
let xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
success && success(xhr.responseText);
resolve(xhr.responseText)
}
};
xhr.onerror = (err) => {
fail && fail(err);
reject(err);
};
xhr.open(method, url, isAsync);
if (headers) {
Object.keys(headers).forEach((key) =>
xhr.setRequestHeader(key, headers[key])
);
}
method === 'GET' ? xhr.send() : xhr.send(data);
});
}
在整个函数外面套一个 Promise, 然后成功时把响应数据传进 resolve, 失败时传进 reject 里
这样就实现了一个简易的 axios, 不足的是错误处理, 返回数据美化等功能没有细致化实现, 如果你感兴趣的话, 可以去看看 axios 的源码, 然后自己动手实现一下