有这样一个面试题目:
有 8 个图片资源的 url,已经存储在数组 urls 中(即urls = [‘http://example.com/1.jpg’, …., ‘http://example.com/8.jpg’]),而且已经有一个函数 function loadImg,输入一个 url 链接,返回一个 Promise,该 Promise 在图片下载完成的时候 resolve,下载失败则 reject。
但是我们要求,任意时刻,同时下载的链接数量不可以超过 3 个。
请写一段代码实现这个需求,要求尽可能快速地将所有图片下载完成。
已有代码如下:
var urls = [
'https://www.kkkk1000.com/images/getImgData/getImgDatadata.jpg',
'https://www.kkkk1000.com/images/getImgData/gray.gif',
'https://www.kkkk1000.com/images/getImgData/Particle.gif',
'https://www.kkkk1000.com/images/getImgData/arithmetic.png',
'https://www.kkkk1000.com/images/getImgData/arithmetic2.gif',
'https://www.kkkk1000.com/images/getImgData/getImgDataError.jpg',
'https://www.kkkk1000.com/images/getImgData/arithmetic.gif',
'https://www.kkkk1000.com/images/wxQrCode2.png'
];
function loadImg(url) {
return new Promise((resolve, reject) => {
const img = new Image()
img.onload = function () {
console.log('一张图片加载完成');
resolve();
}
img.onerror = reject
img.src = url
})
};
看到这个题目的时候,脑袋里瞬间想到了高效率排队买地铁票的情景,那个情景类似下图:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190301121838224.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3Rvbmdob25nbGVp,size_16,color_FFFFFF,t_70#pic_center)
上图这样的排队和并发请求的场景基本类似,窗口只有三个,人超过三个之后,后面的人只能排队了。
于是想到解题的大体思路如下:
首先我们对给出的loadImg函数进行封装,封装的目的有2个:
- 对每次调用该函数加载图片时进行计数,每调用一次数量加1,以保证同时请求的数量不超过要求的数量。
- 在图片加载成功或失败的回调函数中计数减1,表示对某一个图片的处理已经完成,空出了一个位置。然后进行判断,看当前请求的数量是否小于限制数量,并且urls数组里面还有元素,条件成立的话就递归调用本函数。
代码如下:
var total = 3, count = 0
function counterLoad() {
count++
loadImg(urls.shift())
.then(() => {
count--
if(count<total && urls.length) {
counterLoad()
}
})
.catch(err => {
console.log('图片加载失败', err)
count--
if(count<total && urls.length) {
counterLoad()
}
})
}
for(var i=0; i<total; i++) {
counterLoad()
}
此题其他解法可参考原文Promise面试题3控制并发
类比上面的解决办法,可按如下方式并发多个请求
var apis = [
{
apiName: getName,
apiParams: {
gentle: 'male',
age: 18
}
},
{
apiName: getName,
apiParams: {
gentle: 'male',
age: 18
}
},
{
apiName: getName,
apiParams: {
gentle: 'male',
age: 18
}
},
]
var total = 2
var count = 0
function getData(apiConfig) {
return new Promise((resolve, reject) => {
apiConfig.apiName(apiConfig.apiParams).then((res) => {
resolve(res)
}).catch(err => {
console.log('请求出错', err)
resolve()
})
})
}
function CountLimitedRequest() {
count++
console.log('当前正在进行的请求数量为',count)
if(count<=total && apis.length) {
getData(apis.shift())
.then(() => {
count--
CountLimitedRequest()
})
}
}
function start() {
for(var i=0; i<total; i++) {
CountLimitedRequest()
}
}
参考文章:Promise面试题3控制并发
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)