有8个图片资源的url,已经存储在数组urls中。
urls类似于['https://image1.png', 'https://image2.png', ....]
而且已经有一个函数function loadImg
,输入一个url链接,返回一个Promise,该Promise在图片下载完成的时候resolve,下载失败则reject。
但有一个要求,任何时刻同时下载的链接数量不可以超过3个。
请写一段代码实现这个需求,要求尽可能快速地将所有图片下载完成。
1var urls = [ 2 "https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/AboutMe-painting1.png", 3 "https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/AboutMe-painting2.png", 4 "https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/AboutMe-painting3.png", 5 "https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/AboutMe-painting4.png", 6 "https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/AboutMe-painting5.png", 7 "https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/bpmn6.png", 8 "https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/bpmn7.png", 9 "https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/bpmn8.png", 10]; 11function loadImg(url) { 12 return new Promise((resolve, reject) => { 13 const img = new Image(); 14 img.onload = function() { 15 console.log("一张图片加载完成"); 16 resolve(img); 17 }; 18 img.onerror = function() { 19 reject(new Error('Could not load image at' + url)); 20 }; 21 img.src = url; 22 });
参考答案:
既然题目的要求是保证每次并发请求的数量为3,那么我们可以先请求urls中的前面三个(下标为0,1,2),并且请求的时候使用Promise.race()
来同时请求,三个中有一个先完成了,我们就把这个当前数组中已经完成的那一项(第1项)换成还没有请求的那一项(urls中下标为3)。
直到urls已经遍历完了,然后将最后三个没有完成的请求(也就是状态没有改变的Promise)用Promise.all()
来加载它们。
1function limitLoad(urls, handler, limit) { 2 let sequence = [].concat(urls); // 复制urls 3 // 这一步是为了初始化 promises 这个"容器" 4 let promises = sequence.splice(0, limit).map((url, index) => { 5 return handler(url).then(() => { 6 // 返回下标是为了知道数组中是哪一项最先完成 7 return index; 8 }); 9 }); 10 // 注意这里要将整个变量过程返回,这样得到的就是一个Promise,可以在外面链式调用 11 return sequence 12 .reduce((pCollect, url) => { 13 return pCollect 14 .then(() => { 15 return Promise.race(promises); // 返回已经完成的下标 16 }) 17 .then(fastestIndex => { // 获取到已经完成的下标 18 // 将"容器"内已经完成的那一项替换 19 promises[fastestIndex] = handler(url).then( 20 () => { 21 return fastestIndex; // 要继续将这个下标返回,以便下一次变量 22 } 23 ); 24 }) 25 .catch(err => { 26 console.error(err); 27 }); 28 }, Promise.resolve()) // 初始化传入 29 .then(() => { // 最后三个用.all来调用 30 return Promise.all(promises); 31 }); 32} 33limitLoad(urls, loadImg, 3) 34 .then(res => { 35 console.log("图片全部加载完毕"); 36 console.log(res); 37 }) 38 .catch(err => { 39 console.error(err); 40 }); 41
最近更新时间:2024-07-20