资源预解析,写一个?
HardenSG opened this issue · comments
SG commented
当项目中有很多额外的静态资源时候,比如样式表比如图片等。如果将加载的时间交由触发时操作,那么用户就可能白白的等着资源加载出现的转圈圈或者白屏,这显然不是一个成熟的项目该有的样子。
对于项目中可能会使用到的资源,在白屏阶段或者loading阶段就进行预先加载,这在后续的使用时会大大提升响应速度!
为什么会提升响应速度呢?
因为对于这类静态资源来讲,往往都是可以被缓存的,所以也就是说预加载的真正目的其实就是为了触发浏览器的强缓存,这样在后续加载资源的时候就可以直接命中缓存,就不需要发起那该死的网络请求了。
这才是预加载的真正目的!
const ERROR_MSG = {
'ERROR': 'REQUEST_FAIL',
'REDIRECTION': 'REQUEST_REDIRECTION_LOCATION',
'OVERTIME': 'OVER_MAX_RETRY_TIME'
}
const axios = (url, resolve, reject) => {
https.get(url, res => {
res.on('end', () => {
const status = res.statusCode
if(status > 300 && status < 400) {
const location = res.getResponseHeader('Location')
reject(ERROR_MSG.REDIRECTION, location)
}
resolve()
})
}).on('error', (err) => {
reject(ERROR_MSG.ERROR)
})
}
class Scheduler {
constructor(items, options) {
this.options = options
this.reqPools = []
this.Init(items)
}
Init(items) {
this.handleOptions()
if(!Array.isArray(items)) {
throw new Error("NOT A ARRAY FOR THIS VARIABLE")
}
items.forEach(v => {
this.reqPools.push(new SyncPoolItem(v, this.isRetry, this.maxTryTime))
})
}
handleOptions() {
for (const k in this.options) {
if (Object.hasOwnProperty.call(this.options, k)) {
const v = this.options[k];
this[k] = v
}
}
}
run(resolve, rej) {
const maxSync = this['maxSync'] || 5
// Init Container
const container = this.reqPools.splice(0, maxSync)
container.map((v, i) =>
v.run().then(() => {
return i
}).catch(err => {
throw new Error(err)
})
)
// 遍历列表
return new Promise(() => {
this.reqPools.reduce((c, r) => {
return c
.then(() => {
return Promise.race(container)
}).then(i => {
container[i] = r.run().then(res => {
return i
})
}).catch(err => {
rej(err)
})
}, Promise.resolve())
.then(res => {
Promise.all(container).then(res => {
resolve()
}).catch(err => {
rej(err)
})
})
})
}
}
class SyncPoolItem {
constructor(url, isRetry, maxTryTime) {
this.url = url
this.isRetry = isRetry
this.maxTryTime = maxTryTime
this.currentRetryTime = 1
}
// retry's core
async run() {
// console.log(this.isRetry, this.currentRetryTime, this.maxTryTime, this.url);
if(!this.isRetry || this.currentRetryTime >= this.maxTryTime) {
throw new Error(ERROR_MSG.OVERTIME)
}
try {
return await new Promise((resolve, reject) => {
axios(this.url, resolve, reject)
})
} catch (err) {
this.currentRetryTime++
this.run()
}
}
}
/**
* @param urls: string[]
*/
function preload(urls) {
const reqPools = urls.map(v => v)
return async (options) => {
const scheduler = new Scheduler(reqPools, options)
try {
const res = await new Promise((resolve, reject) => {
scheduler.run(resolve, reject)
console.log(2)
})
console.log('res', res)
} catch (err) {
console.log('err', err)
}
}
}
preload(urls)({
maxSync: 5,
isRetry: true,
maxTryTime: 3
}).then(res => {
console.log('res_', res);
}).catch(err => {
console.log('err_', err);
})