消除异步的传染性
前端开发中通常指的是通过一些技术手段,避免异步操作在整个代码库中蔓延,导致原本可以是同步的函数也必须变成异步。
原代码:
async function getUser() {
return await fetch('./1.json)
}
async function m1() {
return await getUser()
}
async function main() {
const data = await m1()
}
重写 fetch:
function getUser() {
return fetch('./1.json)
}
function m1() {
return getUser()
}
function main() {
const user = m1()
console.log(user)
}
function run(func) {
const oldFetch = window.fetch;
const cache = {
status: 'pending', // pending, fulfilled, rejected
value: null
}
function newFetch(...args) {
if(cache.status === 'fulfilled') {
return cache.value;
}
else if (cache.status === 'rejected') {
throw cache.value;
}
const p = oldFetch(...args).then(res=> res.json())
.then(res => {
cache.status = 'fulfilled';
cache.value = res;
})
.catch(err => {
cache.status = 'rejected';
cache.value = err;
})
throw p;
}
window.fetch = newFetch;
try{
func();
}catch(err) {
if(err instaceof Promise) {
err.finally(() => {
window.fetch = newFetch;
func()
window.fetch = oldFetch;
})
}
}
window.fetch = oldFetch;
}
run(main)
什么是 Suspense?
Suspense 是 React 16.6+ 引入的数据获取和代码分割的并发特性,用于更优雅地处理异步操作。在 React 中就是使用了这样的原理
// 使用 Suspense 进行数据获取
import { Suspense } from 'react';
import { fetchData } from './api';
// 创建一个资源
const resource = fetchData('/api/user');
function UserProfile() {
// 读取数据(可能会挂起)
const user = resource.read();
return <div>{user.name}</div>;
}
function App() {
return (
<Suspense fallback={<div>Loading user...</div>}>
<UserProfile />
</Suspense>
);
}
实现 Suspense 数据获取
// 创建资源包装器
function wrapPromise(promise) {
let status = 'pending';
let result;
const suspender = promise.then(
(r) => {
status = 'success';
result = r;
},
(e) => {
status = 'error';
result = e;
}
);
return {
read() {
if (status === 'pending') {
throw suspender; // 这会触发 Suspense
} else if (status === 'error') {
throw result; // 这会触发 Error Boundary
} else if (status === 'success') {
return result;
}
}
};
}
// 使用示例
function fetchUser(id) {
return wrapPromise(
fetch(`/api/user/${id}`).then(res => res.json())
);
}
评论区