6.异步传染
什么是异步传染
异步传染是指如果某个函数用了 async,那么调用它的函数想要得到这个函数的返回值,就必须使用 await 关键字, 要使用 await 关键字,就必须在调用它的函数中使用 async 关键字。
举个例子:
javascript
async function foo() {
return 1;
}
async function bar() {
const result = await foo();
console.log(result);
}
bar(); // 1
bar 函数为了得到 foo 函数的返回值,必须使用 await 关键字。
那么我们有没有什么方式可以用同步的方式调用 foo 函数呢,比如:
javascript
async function foo() {
return 1;
}
function bar() {
const result = foo();
console.log(result);
}
bar(); // 1
foo 函数的执行编程了同步,那么,能不能在 foo 函数的结果出来的时候,再去调用呢,如果是相同的函数,那肯定是悖论,如果我们重写 foo 函数,那么就有可能。
javascript
async function foo() {
return 1;
}
function bar() {
const result = foo();
console.log(result);
}
function run(fn) {
const oldFoo = foo;
let cache = {
status: 'pendding',
data: null
}
foo = function() {
if (cache.status === 'pendding') return cache
throw oldFoo().then(res => {
cache = {
status: 'done',
data: res
}
}).catch(err => {
cache = {
status: 'error',
data: err
}
})
}
try {
fn()
} catch (err) {
err.finally(() => {
fn()
})
}
}
上面的例子很简单,就是针对异步的 foo 做了重写处理,我们模拟正常的接口代码:
javascript
// 我们的 getData 函数是异步的由头,接下来需要针对这个函数做异步传染处理
function getData(time = 1000) {
return new Promise((resolve) => {
setTimeout(() => resolve({ name: "666", count: 0 }), time);
});
}
function p1() {
const res = getData(1500);
return { ...res, count: res.count + 1 };
}
function p2() {
const res = p1();
return { ...res, count: res.count + 1 };
}
// 通过 run 函数对 getData 函数做异步传染处理
function run(fn) {
const oldGetData = getData;
let cache = {
status: "pendding",
data: null,
};
// 重写 getData
getData = function () {
if (cache.status !== "pendding") return cache.data;
// 调用原来的 getData 函数
const p = oldGetData().then(
(res) => {
cache = {
status: "success",
data: res,
};
},
(err) => {
cache = {
status: "fail",
data: err,
};
}
);
// 同步抛出错误,此时 promise 肯定还在 pendding 状态
throw p;
};
try {
// 捕获我们上面抛出的错误,拿到 promise 对象
fn();
} catch (err) {
console.log(err);
err.finally(() => {
// 这里 promise 已经完成,我们重新执行一次 fn 函数即可
fn();
getData = oldGetData;
});
}
}
run(() => {
const data = p2();
console.log(data);
});
总结
异步传染可以用抛出错误的方式处理,但是存在一个非常致命的问题是整个函数链路执行了两次,这会导致性能问题,所以在性能和写法做取舍是我们需要考虑的。