先看下面的代码,由于userInfo是异步的,导致后面调用userInfo的方法以及相关联方法,全都需要使用async,await处理。这就是异步的传染性
async function userInfo() {
// 接口请求
return await (await fetch('./index.json')).json()
}
async function getUser() {
let user = await userInfo()
return user
}
async function m1() {
let user = await getUser()
return user
}
async function main() {
let user = await getUser()
return user
}
main().then(ret => {
console.log(ret)
})
问题
怎么可以消除异步传染呢,在后续函数调用的时候去掉async await
function userInfo() {
return fetch('./index.json')
}
function getUser() {
let user = userInfo()
return user
}
function m1() {
let user = getUser()
return user
}
function main() {
let user = m1()
console.log(user)
}
解决思路
为什么会出现这种情况?因为请求一定会是异步的,为了从根源解决问题,我们改造fetch方法,把fetch方法改成同步的就好了
fetch改造
fetch函数内部使用缓存存储请求结果,当执行fetch函数时:
- 如果请求有缓存就直接使用缓存
- 如果没有缓存
- 直接抛出异常。
- 当前函数继续执行请求,并缓存请求结果
最后,在函数入口处执行函数并捕获异常,如果有异常就在一定时机重新执行函数
// 这里就只考虑一个请求的情况
let oriFetch = window.fetch
let cache = {
status: 'pending',
value: null
}
window.fetch = function(...args) {
if (cache.status === 'fullfilled') {
return cache.value
}
if (cache.status === 'reject') {
throw cache.value
}
let prom = oriFetch(...args).then(ret=> ret.json()).then(ret => {
cache.status = 'fullfilled'
cache.value = ret
}).catch(err => {
cache.status = 'reject'
cache.value = err
})
throw prom
}
function run(func) {
try {
func()
} catch(err) {
if (err instanceof Promise) {
err.then(func, func).finally(() => {
window.fetch = oriFetch
cache.status = 'pending'
cache.value = null
})
}
}
}
run(main)