AJAX、axios、fetch的区别
AJAX
Gmail开发人员发现IE里面有个XMLHTTPRequest
对象来请求数据时,可以实现无刷新数据请求,所以使用这个特性,进行网络数据请求,这就是AJAX
的由来。
AJAX
不是一个单词,他的全称是Asynchronous JavaScript and XML
,就是异步的JavaScript
和XML
,它是一套用于创建快速动态网页的技术标准,使用步骤如下:
创建异步XMLHttpRequest
对象
设置请求参数,包括请求的方法和URL等
发送请求
注册事件,事件状态变更会及时响应监听
在监听里面获取并处理返回数据
所以AJAX
的核心就是XMLHttpRequest
对象,这是一个非常早的实现方法,也是兼容性最好的,已经成为了浏览器标准,虽然我们现在都使用其它的API规范,但对象名字暂时还是用XML
命名
axios
axios
是一个基于Promise
的HTTP
库,可以用在浏览器和node.js
中,它底层还是基于XMLHttpRequest
对象的,你可以认为它是一个方便的封装库,除了基础请求数据,它还增加了如下功能:
对PromiseAPI
的支持
支持请求拦截和响应、转换请求数据和响应数据、取消请求
可以自动转换JSON
数据
支持防御XSRF
fetch
fetch
就不是XMLHttpRequest
对象了,fetch
是原生的js对象,是ES6新增的通信方法。也就是说,它不依赖浏览器,fetch
提供了一个理解的请求替换方案,可以提供给其它技术使用。我们主要需要了解下fetch
和ajax
的本质区别:
fetch
返回的是Promise
,所以如果HTTP状态码是404之类的,fetch也是成功返回的,只有在网络连接错误的情况下,才会reject
fetch
不发送cookies
fetch
的请求写法会比AJAX
简单许多,但我想,最主要的问题是,无法区分HTTP状态码了,这个在编程时还是比较常用的,所以我们目前还是使用axios
比较多,而很少使用fetch
实现
为什么?
我们现在都是单页面应用,需要做并发限制
串行和并行
- 串行:请求是异步的,需要等待上一个请求成功,才能执行下一个请求
- 并行:同时发送多个请求「HTTP请求可以同时进行,但是JS的操作都是一步步的来的,因为JS是单线程」,等待所有请求都成功,我们再去做什么事情?
Promise.all并发限制及async-pool的应用
const delay = function delay(interval) {
return new Promise((resolve, reject) => {
setTimeout(() => {
// if (interval === 1003) reject('xxx');
resolve(interval);
}, interval);
});
};
let tasks = [() => {
return delay(1000);
}, () => {
return delay(1003);
}, () => {
return delay(1005);
}, () => {
return delay(1002);
}, () => {
return delay(1004);
}, () => {
return delay(1006);
}];
/* Promise.all(tasks.map(task => task())).then(results => {
console.log(results);
}); */
let results = [];
asyncPool(2, tasks, (task, next) => {
task().then(result => {
results.push(result);
next(); //执行下一个
});
}, () => {
console.log(results); //所有都完成
});
JS实现Ajax并发请求控制的两大解决方案
// tasks:数组,数组包含很多方法,每一个方法执行就是发送一个请求「基于Promise管理」
function createRequest(tasks, pool) {
pool = pool || 5;
let results = [],
together = new Array(pool).fill(null),
index = 0;
together = together.map(() => {
return new Promise((resolve, reject) => {
const run = function run() {
if (index >= tasks.length) {
resolve();
return;
};
let old_index = index,
task = tasks[index++];
task().then(result => {
results[old_index] = result;
run();
}).catch(reason => {
reject(reason);
});
};
run();
});
});
return Promise.all(together).then(() => results);
createRequest(tasks, 2).then(results => {
// 都成功,整体才是成功,按顺序存储结果
console.log('成功-->', results);
}).catch(reason => {
// 只要有也给失败,整体就是失败
console.log('失败-->', reason);
});
}
function createRequest(tasks, pool, callback) {
if (typeof pool === "function") {
callback = pool;
pool = 5;
}
if (typeof pool !== "number") pool = 5;
if (typeof callback !== "function") callback = function () {};
//------
class TaskQueue {
running = 0;
queue = [];
results = [];
pushTask(task) {
let self = this;
self.queue.push(task);
self.next();
}
next() {
let self = this;
while (self.running < pool && self.queue.length) {
self.running++;
let task = self.queue.shift();
task().then(result => {
self.results.push(result); // 没有管控顺序
}).finally(() => { // 失败之后继续
self.running--;
self.next();
});
}
if (self.running === 0) callback(self.results);
}
}
let TQ = new TaskQueue;
tasks.forEach(task => TQ.pushTask(task));
}
createRequest(tasks, 2, results => {
console.log(results);
});