女娲大战虫族,背后到底有多少故事?
嗨,我是你稳定更新、持续输出的勾勾。
相传远古时代,天塌地陷,世界陷入巨大灾难。女娲不忍生灵受灾,于是炼五色石补好天空,折神鳖之足撑四极,平洪水杀猛兽,通阴阳除逆气,万灵始得以安居。
女娲补天,不仅仅是个神话故事。
女娲补天,事实上补的是虫洞。
神话是上一个纪元的历史,而虫洞的对面是地球的敌人。
所以要补上虫洞,阻断对面虫族的进攻通道。
当科技发展到一定程度,人类会探索到连接不同时空的隧道。
人类通过虫洞可以去到异度空间,而异度空间的朋友也可以来到我们的世界。
当世界与世界,空间与空间之间的道路被打通。
战争一触即发!
双方开战,世界再次陷入混战。
在这个时候,女娲后人血脉觉醒,决定承担起拯救苍生的重任。
这个时候,难题来了。
题目是这样写的:
在 urls 数组中存放了 10 个接口地址。同时还定义了一个 loadDate 函数,这个函数接受一个 url 参数,返回一个 Promise 对象,该 Promise 在接口调用成功时返回 resolve,失败时返回 reject。
要求:任意时刻,同时下载的链接数量不可以超过 3 个。试写出一段代码实现这个需求,要求尽可能快速地将所有接口中的数据得到。
var urls = [
'http://jsonplaceholder.typicode.com/posts/1',
'http://jsonplaceholder.typicode.com/posts/2',
'http://jsonplaceholder.typicode.com/posts/3',
'http://jsonplaceholder.typicode.com/posts/4',
'http://jsonplaceholder.typicode.com/posts/5',
'http://jsonplaceholder.typicode.com/posts/6',
'http://jsonplaceholder.typicode.com/posts/7',
'http://jsonplaceholder.typicode.com/posts/8',
'http://jsonplaceholder.typicode.com/posts/9',
'http://jsonplaceholder.typicode.com/posts/10'
]
function loadDate (url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.onload = function () {
resolve(xhr.responseText)
}
xhr.open('GET', url)
xhr.send()
})
}
这道题目,对很多人真的很难。
但是,难不倒会炼五色石的女娲后人!
因为,他是学前端的!
因为,他是伟大的切图仔!
他缓缓道来:“按照题意,可以这样做。”
首先并发请求 3 个 url 中的数据,当其中一条 url 请求得到数据后,再继续发起对一条 url 上数据的请求。
要始终让并发数保持在 3 个,直到所有需要加载数据的 url 全部都完成请求并得到了数据。
用 Promise 实现的思路是,首先并发请求3个 url ,得到的 3 个 Promise ,然后组成一个叫 promises 的数组。
再不断地调用 Promise.race 来返回最快改变状态的 Promise ,然后从数组 promises 中删掉这个 Promise 对象,再加入一个新的 Promise,直到所有的 url 被取完,最后再使用 Promise.all 来处理一遍数组(promises)中没有改变状态的 Promise。
最终输出如下:
var urls = [
'http://jsonplaceholder.typicode.com/posts/1',
'http://jsonplaceholder.typicode.com/posts/2',
'http://jsonplaceholder.typicode.com/posts/3',
'http://jsonplaceholder.typicode.com/posts/4',
'http://jsonplaceholder.typicode.com/posts/5',
'http://jsonplaceholder.typicode.com/posts/6',
'http://jsonplaceholder.typicode.com/posts/7',
'http://jsonplaceholder.typicode.com/posts/8',
'http://jsonplaceholder.typicode.com/posts/9',
'http://jsonplaceholder.typicode.com/posts/10'
]
function loadDate (url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.onload = function () {
resolve(xhr.responseText)
}
xhr.open('GET', url)
xhr.send()
})
}
function limitLoad(urls, handler, limit) {
// 对数组做一个拷贝
const sequence = [].concat(urls)
let promises = [];
//并发请求到最大数
promises = sequence.splice(0, limit).map((url, index) => {
// 这里返回的 index 是任务在 promises 的脚标,用于在 Promise.race 之后找到完成的任务脚标
return handler(url).then(() => {
return index
});
});
// 利用数组的 reduce 方法来以队列的形式执行
return sequence.reduce((last, url, currentIndex) => {
return last.then(() => {
// 返回最快改变状态的 Promise
return Promise.race(promises)
}).catch(err => {
// 这里的 catch 不仅用来捕获 前面 then 方法抛出的错误
// 更重要的是防止中断整个链式调用
console.error(err)
}).then((res) => {
// 用新的 Promise 替换掉最快改变状态的 Promise
promises[res] = handler(sequence[currentIndex]).then(() => { return res });
})
}, Promise.resolve()).then(() => {
return Promise.all(promises)
})
}
limitLoad(urls, loadDate, 3)
/*
因为 loadDate 函数也返回一个 Promise,所以当 所有图片加载完成后,可以继续链式调用
limitLoad(urls, loadDate, 3).then(() => {
console.log('所有url数据请求成功');
}).catch(err => {
console.error(err);
})
*/
答案出来了,虫洞也终于补上了!
而全世界人类因为受到异族的荼毒,得上了重病。
为了医治全人类,科学家研发出了疫苗,需要女娲后人动用古老的力量传播给所有人。
女娲后人用最普遍存在的介质,也就是泥土做为媒介,承载着疫苗,飞天泼洒。
于是有了女娲补天、女娲造人的历史记载。
在数万年人们的口口相传中,女娲逐渐被神化。
历史便成了传说。
悟空,你悟了吗?
推荐阅读:
前端人因为 Vue3 的 Ref-sugar 提案打起来了!
点点“赞”和“在看”,保护头发,减少bug。