javascript如何实现惰性加载_它如何提升单页面应用的性能?
夢幻星辰
发布时间:2026-01-09 15:24:09
|
267人浏览过
|
来源于php中文网
原创
import() 是 JavaScript 动态导入语法,用于运行时按需加载模块,返回 Promise,支持条件判断、变量路径和任意作用域调用,区别于顶层静态 import。

什么是 import() 动态导入?
JavaScript 的 import() 是一个函数式语法,用于在运行时按需加载模块,而不是在模块初始化时就全部加载。它返回一个 Promise,这意味着你可以用 await 或 .then() 处理加载完成后的逻辑。
它和静态 import 语句有本质区别:静态导入必须写在顶层、不能加条件;而 import() 可以出现在任意作用域,支持变量拼接路径、条件判断、循环调用等。
- ✅ 支持字符串模板:
import(`./pages/${pageName}.js`)
- ❌ 不支持表达式以外的路径:比如
import(someVar) 中 someVar 必须是可静态分析的字符串(Webpack/Vite 会尝试做预构建,但太动态会 fallback 到 runtime 请求)
- ⚠️ 浏览器原生支持,但旧版 Safari(
怎么在 React 路由中用 React.lazy + Suspense 实现路由级懒加载?
React.lazy 是对 import() 的封装,专为组件懒加载设计;Suspense 则负责处理加载中的 UI 状态。两者必须配合使用,且 Suspense 必须包裹其子组件(不能包裹 lazy 组件本身)。
const Home = React.lazy(() => import('./pages/Home'));
const About = React.lazy(() => import('./pages/About'));
function App() {
return (
Loading...
}>
} />
} />
);
}
- ⚠️
React.lazy 只支持默认导出(export default),不支持命名导出(export const X),否则会报 undefined is not a component
- ⚠️
Suspense 在服务端渲染(SSR)中不生效,需搭配 loadable-components 或 @loadable/component 做降级
- ? 可把
fallback 提取为独立 Loading 组件,避免内联 JSX 影响可维护性
为什么不用 require.ensure 或 System.import?
这两个都是 Webpack 早期的私有 API,已废弃多年。require.ensure 是 Webpack 1–2 的产物,System.import 曾短暂作为提案,但被标准 import() 取代。现代打包工具(Vite/Webpack 5+)只识别 import() 并自动切分 chunk。
立即学习“Java免费学习笔记(深入)”;
- ?
require.ensure 在 Webpack 5 中已被移除,强行使用会报 require is not defined(ESM 环境下)
- ?
System.import 在 Chrome 63+ 已弃用,控制台会警告 System is not defined
- ✅ 所有主流构建工具对
import() 的代码分割(code splitting)支持成熟,chunk 名称、预加载、prefetch 都可通过 magic comments 控制,例如:/* webpackPrefetch: true */
懒加载不是万能的——哪些情况反而会拖慢首屏?
过度拆分或错误触发时机,会让懒加载从优化变成负优化。关键看资源是否「真·非首屏必需」。
- ❌ 把按钮点击就立刻用到的组件(如弹窗表单)设为懒加载:用户点一下才开始请求 JS,感知延迟明显
- ❌ 在
useEffect 中无节制调用 import():可能触发多次重复加载,或与 React 渲染周期错拍,导致白屏或状态丢失
- ✅ 合理场景:路由切换、Tab 标签页切换、折叠面板展开、图片/视频播放器初始化
- ? 可结合
webpackChunkName 注释让 chunk 更易识别:import(/* webpackChunkName: "chart-lib" */ 'echarts')
真正影响性能的,往往不是“有没有懒加载”,而是“什么时候加载”和“加载了什么”。比如一个 50KB 的工具函数被拆进每个路由 chunk,不如统一放 vendor;而一个 300KB 的图表库,只在特定页面用,就值得单独拆。