使用Promise实现:限制异步操作的并发个数,并尽可能快的完成全部
题目
有8个图片资源的url,已经存储在数组urls中。
urls类似于[‘https://image1.png', ‘https://image2.png', ….]
而且已经有一个函数function loadImg,输入一个url链接,返回一个Promise,该Promise在图片下载完成的时候resolve,下载失败则reject。
但有一个要求,任何时刻同时下载的链接数量不可以超过3个。
请写一段代码实现这个需求,要求尽可能快速地将所有图片下载完成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| var urls = [ "https://byr.vercel.app/static/img/page14/1.jpg", "https://byr.vercel.app/static/img/page14/1.jpg", "https://byr.vercel.app/static/img/page14/1.jpg", "https://byr.vercel.app/static/img/page14/1.jpg", "https://byr.vercel.app/static/img/page14/1.jpg", "https://byr.vercel.app/static/img/page14/1.jpg", "https://byr.vercel.app/static/img/page14/1.jpg", "https://byr.vercel.app/static/img/page14/1.jpg", ];
function loadImg(url) { return new Promise((resolve, reject) => { const img = new Image(); img.onload = function () { console.log("一张图片加载完成"); resolve(img); }; img.onerror = function () { reject(new Error('Could not load image at' + url)); }; img.src = url; }) };
|
解题
既然题目的要求是保证每次并发请求的数量为3, 那么我们可以先请求urls中的前面三个(下标为0, 1, 2)。
并且请求的时候使用Promise.race()
来同时请求, 三个中有一个先完成了, 我们就把这个当前数组中已经完成的那一项(第1项) 换成还没有请求的那一项(urls中下标为3)。
直到urls已经遍历完了, 然后将最后三个没有完成的请求(也就是状态没有改变的Promise) 用Promise.all()
来加载它们。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| function limitLoad(urls, handler, limit) { let sequence = [].concat(urls); let promises = sequence.splice(0, limit).map((url, index) => { return handler(url).then(() => { return index; }); }); return sequence .reduce((pCollect, url) => { return pCollect .then(() => { return Promise.race(promises); }) .then(fastestIndex => { promises[fastestIndex] = handler(url).then( () => { return fastestIndex; } ); }) .catch(err => { console.error(err); }); }, Promise.resolve()) .then(() => { return Promise.all(promises); }); } limitLoad(urls, loadImg, 3) .then(res => { console.log("图片全部加载完毕"); console.log(res); }) .catch(err => { console.error(err); });
|