前言
今天去一个公司面试前端的时候,遇到这样一个问题: 假设我们有一个接口,getJson('story.json'),可以请求一个故事的所有章节对应的url的列表(按章节顺序排序);而每一章节的内容,我们可以请求getJson(url)得到,如今等到我们的需求是:并发请求所有章节的内容,为了得到更好的用户体验,我们应该及时的按顺序显示章节内容,也就是说不能等到收到所有章节内容在显示,函数addTextTopage(chapter)可以展示一章内容,请根据以上需求把下面代码补充完整
getJson('story.json')
.then(function (story) {
addHtmlToPage(story.heading)
const allUrls = story.chapterUrls
// 请在此处补充代码
})
.then(function () {
addTextToPage('All Done')
})
.catch(function (err) {
// catch any error that happend along the way
addTextToPage('Argh, broken' + err.message)
})
.then(function () {
document.querySelector('.spinner').style.display = 'none'
})
思路分析
- 通过批量并且当所有请求结束后,在执行 callback 我们初步确定使用 Promise.all 可以实现此功能,
- 由于请求地址在 urls 数组中,因为是一个并行的问题,所以我们可以将请求地址进行按照 max 来进行分组,最后得到多少组就执行多少次请求
题解
getJson('story.json')
.then(function (story) {
addHtmlToPage(story.heading)
const allUrls = story.chapterUrls
// 请在此处补充代码
// 先定义一个分组函数
let max = 4
function group(allUrls, max) {
let groupObj = {}
allUrls.forEach((item, index) => {
// 进行分组
let group = parseInt(index / max)
// 判断groupObj[group]是否为true,不为true就把item变为一个数组给groupObj[group],然后同一个group的其他item在为true的情况下都push进行
if (groupObj[group]) {
return groupObj[group].push(item)
}
groupObj[group] = [item]
})
return groupObj
}
function sendRequest(allUrls, max,callback) {
// 得到分组
let groupResult = group(allUrls, max)
let currentIndex = 0
function getData(source) {
return source.map( url => getJson(url))
}
function send() {
// 判断当前有没有数组
gruopResult[currentIndex] && Promise.all(getData(gruopResult[currentIndex]))
.then (
(data)=>{
data.forEach((chapter) => {
callback(chapter)
})
})
currentIndex++
// 递归调用,这个很重要
send()
}
send()
}
sendRequest(urls, max, addTextToPage)
})
.then(function () {
addTextToPage('All Done')
})
.catch(function (err) {
// catch any error that happend along the way
addTextToPage('Argh, broken' + err.message)
})
.then(function () {
document.querySelector('.spinner').style.display = 'none'
})