FE-Interview
FE-Interview copied to clipboard
请实现如下的函数
/*
可以批量请求数据,所有的 URL 地址在 urls 参数中,同时可以通过 max 参数控制请求的并发度,当所有请求结束之后,需要执行 callback 回调函数。发请求的函数可以直接使用 fetch 即可
*/
扫描下方二维码,获取答案以及详细解析,同时可解锁800+道前端面试题。
为了避免使用全局变量,我们首先使用闭包的形式
function request(urls, max, callback) {
let len = urls.length;
let currentUrlIndex = 0;
let counter = 0;
return function () {
function batch() {
while (currentUrlIndex < len) {
if (counter <= max) {
myFetch(urls[currentUrlIndex]);
counter++;
}
currentUrlIndex++;
if (counter === max) {
counter = 0;
console.log('执行了一个批量')
break;
}
}
doBatch();
}
function doBatch() {
if (currentUrlIndex < len) {
batch()
} else {
callback()
}
}
doBatch();
}
}
function myFetch(url) {
console.log(url + '执行了')
}
function cb() {
console.log('所有的都结束了')
}
var urls = ['url1', 'url2', 'url3', 'url4', 'url5', 'url6', 'url7']
var fn = request(urls, 4, cb);
fn();
// 优化一下,封装成类
function Request(urls, max, callback) {
this.urls = urls;
this.max = max;
this.callback = callback;
this.len = urls.length;
this.currentUrlIndex = 0;
this.counter = 0;
}
Request.prototype.batch = function (params) {
while (this.currentUrlIndex < this.len) {
if (this.counter < this.max) {
myFetch(this.urls[this.currentUrlIndex]);
this.counter++;
}
this.currentUrlIndex++;
if (this.counter === this.max) {
this.counter = 0;
break;
}
}
this.doBatch();
}
Request.prototype.doBatch = function () {
if (this.currentUrlIndex < this.len) {
this.batch()
} else {
this.callback()
}
}
function myFetch(url) {
console.log(url + '执行了')
}
function cb() {
console.log('所有的都结束了')
}
var urls = ['url1', 'url2', 'url3', 'url4', 'url5', 'url6', 'url7']
var request = new Request(urls, 3, cb);
request.doBatch()
const batchFetch = (urls = [], max = 3, callback) => {
if (!callback) {
throw new Error("Must set callback");
}
/**
* @param urlsLenght 总请求数量
* @param pendingFetchNums 进行中的请求数量
* @param resolvedFetchNums 结束的请求数量
* @param resolvedFetchs 保存请求结果
*/
const urlsLenght = urls.length;
let pendingFetchNums = 0;
let lastFetchIndex = 0;
let resolvedFetchs = new Map();
const doBatch = () => {
while (pendingFetchNums < max && lastFetchIndex < urlsLenght) {
const url = urls[lastFetchIndex];
pendingFetchNums++;
lastFetchIndex++;
console.log(
`DEBUG
pendingFetchNums ${pendingFetchNums}
lastFetchIndex: ${lastFetchIndex}
url: ${url}`
);
Promise.resolve(url).then(result => {
pendingFetchNums--;
resolvedFetchs.set(url, result);
console.log(
`Success get ${url} result: ${result}, current resolved urls size: ${resolvedFetchs.size}, all fetch length: ${urlsLenght}`
);
if (resolvedFetchs.size === urlsLenght) {
const result = [...resolvedFetchs.values()];
console.log(
`All promise successed resolved, should do callback handle, callback result: `,
result
);
return callback(result);
} else {
doBatch();
}
});
}
};
doBatch();
};
保存了每个请求的结果,并在调用 callback 的时候一起入参 为了方便测试,用 Promise.resolve 模拟 fetch 可以自行修改下