react内置的Suspense组件有一个“新颖”的功能就是可以用同步的写法来写异步代码。例:
function ProfileDetails() {
const user = resource.user.read(); // 这一步包含异步从服务端获取数据
return <h1>{user.name}</h1>;
}
上述代码在不用Suspense组件时,一般情况下会认为应该这么写:
async function ProfileDetails() {
const user = await resource.user.read();
return <h1>{user.name}</h1>;
}
但react用一种独特的方式绕过了async,await语法,下面我来模拟实现下:
首先写一个异步函数:
const fetchData = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('我是数据')
}, 1000);
});
}
在写一个wrap函数,用于将普通的异步函数包装为Suspense需要用到的格式。
const wrap = (prms) => {
let status = 'pending';
let result;
prms.then((r) => {
result = r;
status = 'success';
},
(err) => {
result = err;
status = 'error'
});
return () => {
if (status === 'pending') {
throw prms; // 此处为重点
}
if (status === 'error') {
throw result;
}
return result;
}
}
先写一个组件,此组件是我们最终想达到的效果:
const tryReadData = wrap(fetchData()); // 获取包装后的函数
const reactComponent = () => {
const data = tryReadData(); // 需要满足不写await,但需要获取到最终数据
return <div>{data}</div>
}
具体实现:
try {
reactComponent()
} catch(err) {
if (err instanceof Promise) {
// 如果捕获到的错误是个Promise类型,则说明异步还未完成
// 等待异步完成在重新执行组件函数。
err.then(reactComponent)
} else if (err instanceof Error) {
throw err;
} else {
...
}
}