在 JavaScript 中,异步函数的传染性指的是当一个函数内部包含异步操作(例如使用了 Promise、async/await 等)时,它会将异步特性传递给调用它的函数,以及调用它们的函数,依次传递下去。这可能会导致整个调用链上的函数都需要处理异步操作。
考虑以下示例:
async function getUser() {
return await fetch('./data.json').then((res) => res.json());
}
async function m1() {
return await getUser();
}
async function m2() {
return await m1();
}
async function m3() {
return await m2();
}
async function main() {
const user = await m3();
console.log(user)
}
main();
在业务场景中为了解决这个问题,可以使用以下函数,其原理是:使用报异常的方式终止代码继续运行,在异常结束之后获取上吃抛异常时得到的接口请求数据重新执行一遍函数。
由于针对的是纯函数,进参相同,结果也相同,所以无需担心执行后出现副作用。
function getUser() {
return fetch('./data.json')
}
function m1() {
return getUser();
}
function m2() {
return m1();
}
function m3() {
return m2();
}
function main() {
const user = m3()
console.log(user)
}
//改变fetch函数的行为
function run(func) {
let cache = [];//存储缓存结果;
let i = 0;//表示第几次调用fetch
const _originalFetch = window.fetch;
window.fetch = (...args) => {
//有缓存的话就交付缓存结果
if (cache[i]) {
if (cache[i].status === 'fulfilled') {
return cache[i].data;
}
else if (cache[i].status === 'rejected') {
throw cache[i].err;
}
}
//没有缓存就定一个,加到缓存中
const result = {
status: 'padding',
data: null,
err: null
};
cache[i++] = result;
//发送情求
const prom = _originalFetch(...args).then(res => res.json()).then(
res => {
result.status = 'fulfilled';
result.data = res;
console.log("res--->", res)
}, err => {
result.status = 'rejected';
result.data = err;
console.log("err--->", err)
}
)
//报错
throw prom;
};
try {
func()
} catch (err) {
//TODO handle the exception
if (err instanceof Promise) {
const reRun = () => {
i = 0;
func();
}
err.then(reRun, reRun);
}
}
}
run(main);