消除异步的传染性
异步的传染性:由于 getUser 是一个异步函数,则使用 getUser 的一系列函数都要加上 async await ,这就导致原来的纯函数变成了有副作用的函数
需要在不侵入原函数的情况下,消除异步的传染性(react 中常用这种思想)
async function getUser() {
return await fetch('https://my-json-server.typicode.com/typicode/demo/profile').then(resp => resp.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);
}
思路分析
由于第一次请求,没有缓存,则直接 promise 报错,捕获 promise 报错后发起下一次请求,第一次请求的结果会放到缓存中;
由于报错后会发起第二次请求,这时存在第一次的缓存,则直接取值(第一次请求的结果),函数结束;
实现
function getUser() {
return fetch('https://my-json-server.typicode.com/typicode/demo/profile');
}
function m1() {
return getUser();
}
function m2() {
return m1();
}
function m3() {
return m2();
}
function main() {
const user = m3();
console.log(user);
}
function run(func) {
let cache = []; // 缓存结果
let i = 0; // 第几次运行
const _originFetch = 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: 'pending',
data: null,
err: null,
};
cache[i++] = result;
const prom = _originFetch(...args)
.then(resp => resp.json())
.then(
(resp) => {
result.status = 'fulfilled';
result.data = resp;
},
(err) => {
result.status = 'rejected';
result.err = err;
}
)
// fix: 第一次运行的时候直接报错,后面捕获指定的 promise 错误重新运行
throw prom;
};
try {
func();
} catch (err) {
// 什么时候引发重新执行 func()
if (err instanceof Promise) {
const reRun = () => {
i = 0;
func();
};
// 上一次请求成功后,继续发出第二次请求
err.then(reRun, reRun);
}
}
}
run(main);
进阶技巧🕴️ 设计一个并发 api
上一篇