JavaScript 实现模块懒加载的几种方式
懒加载是现代前端性能优化的重要手段,以下是几种常见的 JavaScript 懒加载实现方式:
1. 原生 ES 模块动态导入 (推荐)
ES2020 引入的动态 import()
语法是目前最标准的懒加载方式:
javascript
// 按需加载模块
button.addEventListener('click', async () => {
const module = await import('./module.js');
module.doSomething();
});
特点:
- 返回 Promise
- 浏览器原生支持
- 与打包工具(Webpack/Rollup)完美配合
- 支持代码分割(code splitting)
2. Webpack 的 require.ensure (旧版)
Webpack 特有的异步加载方式(现在已被动态导入取代):
javascript
// Webpack特有的语法
button.addEventListener('click', () => {
require.ensure([], function(require) {
const module = require('./module');
module.doSomething();
}, 'my-chunk-name');
});
3. 动态 script 标签插入
传统方式,适用于非模块化脚本:
javascript
function loadScript(src, callback) {
const script = document.createElement('script');
script.src = src;
script.onload = () => callback();
document.head.appendChild(script);
}
// 使用
button.addEventListener('click', () => {
loadScript('module.js', () => {
// 模块加载完成后执行
window.myModule.doSomething();
});
});
4. AMD (RequireJS) 方式
异步模块定义规范:
javascript
// 定义模块
define('myModule', ['dependency'], function(dependency) {
return {
doSomething: function() { /*...*/ }
};
});
// 加载模块
require(['myModule'], function(myModule) {
myModule.doSomething();
});
5. 懒加载 React/Vue 组件
React 懒加载
jsx
import React, { lazy, Suspense } from 'react';
const LazyComponent = lazy(() => import('./LazyComponent'));
function MyComponent() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}
Vue 懒加载
javascript
const LazyComponent = () => import('./LazyComponent.vue');
new Vue({
components: {
LazyComponent
}
});
6. 高级用法:预加载 + 懒加载
结合预加载提示优化用户体验:
javascript
// 在空闲时预加载
const preloadLink = document.createElement('link');
preloadLink.rel = 'preload';
preloadLink.as = 'script';
preloadLink.href = 'module.js';
document.head.appendChild(preloadLink);
// 实际使用时直接执行
button.addEventListener('click', async () => {
const module = await import('./module.js');
module.doSomething();
});
7. 性能优化技巧
-
代码分割:合理划分懒加载模块边界
-
预加载 :使用
<link rel="preload">
或webpackPrefetch
-
加载状态:显示加载指示器提升用户体验
-
错误处理:捕获加载失败情况
javascriptimport('./module.js') .then(module => { /*...*/ }) .catch(err => { /* 处理错误 */ });
-
命名chunk:方便调试和长期缓存
javascriptimport(/* webpackChunkName: "my-chunk" */ './module.js')
实际应用示例
javascript
// 懒加载图片
const lazyImages = document.querySelectorAll('img[data-src]');
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
imageObserver.unobserve(img);
}
});
});
lazyImages.forEach(img => imageObserver.observe(img));
// 懒加载功能模块
const loadAnalytics = () => import('./analytics')
.then(module => module.init())
.catch(() => console.log('Analytics failed to load'));
window.addEventListener('scroll', () => {
if (window.scrollY > 1000) {
loadAnalytics();
window.removeEventListener('scroll', loadAnalytics);
}
});
注意事项
- 浏览器兼容性 :动态
import()
在较新浏览器中支持 - SEO影响:懒加载内容可能不被搜索引擎抓取
- 状态管理:懒加载模块的初始化状态需要特别处理
- 依赖管理:确保懒加载模块的依赖已加载