AJAX并发请求控制

AJAX、axios、fetch的区别

AJAX

Gmail开发人员发现IE里面有个XMLHTTPRequest对象来请求数据时,可以实现无刷新数据请求,所以使用这个特性,进行网络数据请求,这就是AJAX的由来。
AJAX不是一个单词,他的全称是Asynchronous JavaScript and XML,就是异步的JavaScriptXML,它是一套用于创建快速动态网页的技术标准,使用步骤如下:

创建异步XMLHttpRequest对象
设置请求参数,包括请求的方法和URL等
发送请求
注册事件,事件状态变更会及时响应监听
在监听里面获取并处理返回数据

所以AJAX的核心就是XMLHttpRequest对象,这是一个非常早的实现方法,也是兼容性最好的,已经成为了浏览器标准,虽然我们现在都使用其它的API规范,但对象名字暂时还是用XML命名

axios

axios是一个基于PromiseHTTP库,可以用在浏览器和node.js中,它底层还是基于XMLHttpRequest对象的,你可以认为它是一个方便的封装库,除了基础请求数据,它还增加了如下功能:

PromiseAPI的支持
支持请求拦截和响应、转换请求数据和响应数据、取消请求
可以自动转换JSON数据
支持防御XSRF

fetch

fetch就不是XMLHttpRequest对象了,fetch是原生的js对象,是ES6新增的通信方法。也就是说,它不依赖浏览器,fetch提供了一个理解的请求替换方案,可以提供给其它技术使用。我们主要需要了解下fetchajax的本质区别:

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

你可能感兴趣的:(javaScript,ajax,前端)