JavaScript懒加载组件:异步导入前如何检查模块是否已导入?
实现可复用的JS懒加载组件:避免重复加载时的短暂Loading
我正在创建一个懒加载组件,问题针对JavaScript本身,而非React、Svelte等特定框架,伪代码如下:
const myLazyLoadedComponent = () => { let myComponent let isLoading = true import('/some/path.xx').then(c => { myComponent = c isLoading = false }) // 以下部分与上述变量响应式关联: return ( isLoading ? <div>Loading..</div> : <myComponent/> ) }
首次运行时代码表现正常,但关闭重开或打开组件的另一个实例时,Loading..会短暂显示后才渲染组件。
是否有办法先检查模块是否已导入,再据此决定直接使用模块还是执行异步import()?
我预想的逻辑如下:
if (isAlreadyImported('/some/path.xx')) { import { myComponent } from '/some/path.xx' } else { isLoading = true import('/some/path.xx').then(c => { myComponent = c isLoading = false }) }
当然可以实现,核心思路是缓存已加载的模块,避免重复发起异步请求。JavaScript本身没有内置的isAlreadyImported方法,但我们可以自己维护一个缓存容器来记录已加载的模块。
具体实现方案
- 创建一个跨实例共享的缓存对象,用模块路径作为键,存储已加载的模块或加载中的Promise
- 组件初始化时先检查缓存:存在则直接用模块,不存在则发起
import()并缓存请求过程
优化后的伪代码
// 模块缓存,放在组件外部确保跨实例共享 const moduleCache = new Map() const myLazyLoadedComponent = () => { let myComponent let isLoading = false const modulePath = '/some/path.xx' // 检查缓存 if (moduleCache.has(modulePath)) { const cached = moduleCache.get(modulePath) // 区分缓存的是已加载完成的模块还是加载中的Promise if (cached instanceof Promise) { isLoading = true cached.then(c => { myComponent = c isLoading = false }) } else { myComponent = cached } } else { isLoading = true // 发起请求并缓存Promise,防止多个实例重复加载 const loadPromise = import(modulePath).then(c => { myComponent = c // 加载完成后替换缓存为模块本身 moduleCache.set(modulePath, c) isLoading = false }) moduleCache.set(modulePath, loadPromise) } // 响应式渲染部分 return ( isLoading ? <div>Loading..</div> : <myComponent/> ) }
关键细节说明
- 缓存加载中的Promise:当多个组件实例同时触发加载时,只会发起一次
import()请求,后续实例等待同一个Promise完成,避免重复网络请求 - 缓存放在组件外部:确保关闭重开或新实例能直接读取已加载的模块,彻底消除重复Loading
- 错误处理(可选):可以在
import()的catch中清除缓存里的失败Promise,方便后续重试
内容的提问来源于stack exchange,提问作者Juan Perez
相关产品推荐
相关产品推荐

