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);
});