【发布时间】:2021-12-10 04:16:00
【问题描述】:
据我了解,useEffect 中的异步代码运行时不会阻塞渲染过程。所以如果我有这样的组件:
const App = () => {
useEffect(() => {
const log = () => console.log("window loaded");
window.addEventListener("load", log);
return () => {
window.removeEventListener("load", log);
};
}, []);
useEffect(() => {
const getData = async () => {
console.log("begin");
const response = await fetch(
"https://jsonplaceholder.typicode.com/todos/1"
);
const data = await response.json();
console.log("end");
};
getData();
}, []);
return null;
};
控制台输出为(按顺序):
begin window loaded end
但是,如果我在 useEffect 中使用 ES2020 动态导入:
const App = () => {
useEffect(() => {
const log = () => console.log("window loaded");
window.addEventListener("load", log);
return () => {
window.removeEventListener("load", log);
};
}, []);
useEffect(() => {
const getData = async () => {
console.log("begin");
const data = await import("./data.json");
console.log("end");
};
getData();
}, []);
return null;
};
输出是(按顺序):
begin end window loaded
这是一个问题,因为当data.json 非常大时,浏览器会在 React 渲染之前导入大文件时挂起。
【问题讨论】:
-
如果操作非常繁重(例如加载数据),任何在 UI 线程中运行的东西都会阻塞渲染。您应该将负载卸载到 Web Worker,这样它就不会阻塞 UI 线程。
-
@Terry 但浏览器不应该先完成加载,然后在导入数据时 UI 冻结吗?
-
窗口
load事件在页面生命周期的后期触发,因为它等待所有资源/资产被加载。在您的情况下,在触发窗口加载事件之前,fetch()操作已经返回了响应(但您的 UI 线程在接收和处理响应时锁定)。 -
@Terry 哦,好的,感谢您提供的信息。理想情况下,出于 SEO 原因,我想在加载窗口后导入数据。我不介意页面冻结一点。
-
那你不应该在
load事件监听回调中这样做吗?
标签: javascript reactjs use-effect code-splitting dynamic-import