在网站加载100张图片并同时控制最多只发出四个请求的场景中,当一个请求提前返回时,你需要确保剩余的图片请求能够填补这个‘空位’,以保持并发数始终是四(直到所有图片都被请求)。这通常涉及到一种队列管理机制,用于追踪哪些图片已经被请求,哪些还在队列中等待。
以下是一个简化的概念性实现,使用Javascript(可能是Node.js环境,因为浏览器端对并发请求的控制相对有限)和Promise队列:
class ImageLoader {
constructor(concurrency = 4) {
this.concurrency = concurrency;
this.queue = [];
this.activeCount = 0;
}
loadImage(url) {
return new Promise((resolve, reject) => {
// 假设这里使用fetch来加载图片,但注意fetch本身并不直接处理二进制数据为Image对象
// 在这里,我们只是模拟加载过程
setTimeout(() => {
// 模拟网络延迟,随机时间返回
const delay = Math.random() * 2000;
console.log(`Image${url} loaded after ${delay}ms`);
resolve(`Data for ${url}`);
}, Math.random() * 2000);
})
}
enqueue(url) {
return new Promise((resolve, reject) => {
this.queue.push(() => {
this.activeCount++;
this.loadImage(url)
.then(data => {
this.activeCount--;
resolve(data);
// 如果队列不为空且并发数小于限制,则据继续加载
if (this.queue.length > 0 && this.activeCount < this.concurrency) {
this.dequeue();
}
})
.catch(error => {
this.activeCount--;
reject(error);
// 如果出错,也可以考虑从队列中移除当前任务或重试
if (this.queue.length > 0 && this.activeCount < this.concurrency) {
this.dequeue();
}
})
})
// 如果当前并发数小于限制,则立即开始加载
if (this.activeCount < this.concurrency) {
this.dequeue();
}
});
}
dequeue() {
if (this.queue.length > 0) {
const task = this.queue.shift();
task();
}
}
loadImages(urls) {
const promises = urls.map(url => this.enqueue(url));
return Promise.all(promises);
}
}
// 使用实例
const imageLoader = new ImageLoader(4);
const imageUrls = Array.from({ length: 100 }, (_, i) => `image${i + 1}.jpg`);
imageLoader.loadImages(imageUrls)
.then(results => {
console.log('All images loaded:', results);
})
.catch(error => {
console.error('Error loading images:', error);
});
注意:
1.在这个示例中,loadImage函数模拟了图片的加载过程,使用setTimeout来模拟网络延迟。
2.enqueue方法将加载任务添加到队列中,并检查是否可以立即开始执行(即并发数未达到限制)。
3.当一个图片加载完成后(无论是成功还是失败),都会检查队列中是否有更多的任务可执行,并保持并发数。
4.loadImages方法为所有URL创建了一个Promise数组,并使用Promise.all来等待所有图片加载完成。
这个实现确保了在任何时候最多只有四个图片加载任务在同时进行,并且当一个任务完成时,会立即从队列中取出下一个任务来填补空位。