什么是异步传染性?
async function doRequest() {
await fetch('https://jsonplaceholder.typicode.com/todos/1').then((resp) => resp.json())
}
async function m1() {
return await doRequest();
}
async function m2() {
return await m1();
}
async function m3() {
return await m2();
}
- fetch这个节点是异步的造成了连锁反应
- 一个节点发生了异步,这个节点的所有调用链路全部都得异步
- 函数式编程的场景,m1、m2、m3就不是纯函数了,全部变成了副作用
目标
- 去掉所有的async await,改成同步调用
- 直接返回结果(ps: 异步的怎么会马上、立刻、直接返回结果呢?)
function doRequest() {
return fetch('https://jsonplaceholder.typicode.com/todos/1');
}
function m1() {
return doRequest();
}
function m2() {
return m1();
}
function m3() {
return m2();
}
function main() {
const res = m3();
console.log(res);
}
怎么消除异步?
- 异步肯定不能马上、立刻、直接返回结果
- 只有报错这一条路
- 把promise作为异常抛出

function doRequest() {
return fetch('https://jsonplaceholder.typicode.com/todos/1');
}
function m1() {
return doRequest();
}
function m2() {
return m1();
}
function m3() {
return m2();
}
function main() {
const res = m3();
console.log(res);
}
function run(func) {
let cache = [];
let i = 0;
let _originFetch = window.fetch;
window.fetch = (...args) => {
if (cache[i]) {
if (cache[i].status === 'fullfilled') {
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 promise = _originFetch(...args)
.then(resp => resp.json())
.then(resp => {
result.status = 'fullfilled';
result.data = resp;
}, err => {
result.status = 'rejected';
result.err = err;
});
throw promise;
}
try {
func();
} catch (err) {
if (err instanceof Promise) {
const reRun = () => {
i = 0;
func()
}
err.then(reRun, reRun);
}
}
}
run(main);
React中的应用
const userResource = get UserResource();
function ProfilePage () {
return (
<Suspense fallback={<h1>Loading...</h1>}>
<ProfileDetails />
</Suspense>
)
}
function ProfileDetails () {
console.log(1)
const user = userResource.read();
return <h1>{user.name}</h1>
}
- Suspense里面子组件ProfileDetails的状态,请求中就显示loading,返回结果后就显示用户详情
- React中ProfileDetails组件没有返回Promise,就是一个普通的组件
- 1会打印两次
- 和上面的原理一样,先执行ProfileDetails,会打印第一次,直接throw一个promoise的异常
- 成功后继续再执行一次,然后打印第二次