Dynamic import() function
Basic Concepts of the Dynamic import() Function
The dynamic import()
function introduced in ECMAScript 6 revolutionized the way modules are loaded. While traditional static import
statements must be used at the top level of a module, dynamic import()
can be called anywhere in the code and returns a Promise object. This flexibility enables on-demand module loading, making it particularly useful for optimizing large-scale applications.
// Static import
import { moduleA } from './moduleA.js';
// Dynamic import
const module = await import('./moduleB.js');
Differences from Static import
Static import
determines dependencies during the compilation phase, and all modules are bundled. In contrast, dynamic import()
loads modules at runtime, leading to several key distinctions:
- Static
import
must appear at the top level of a module, while dynamicimport()
can be used anywhere, including inside functions or conditional statements. - Static
import
is a synchronous operation, whereas dynamicimport()
returns a Promise. - Static
import
requires a string literal as the path, while dynamicimport()
can accept variables. - Static
import
triggers preloading of all dependent modules, while dynamicimport()
enables on-demand loading.
// Static import error example
if (condition) {
import './module.js'; // Error: import must appear at the top level
}
// Correct usage of dynamic import
if (condition) {
const module = await import('./module.js');
}
Basic Usage and Syntax
The syntax of the dynamic import()
function is straightforward. It takes a module path as an argument and returns a Promise object. When the module is loaded, the Promise resolves to the module object.
// Basic usage
import('./module.js')
.then(module => {
console.log(module.default);
console.log(module.namedExport);
})
.catch(err => {
console.error('Module loading failed', err);
});
// With async/await
async function loadModule() {
try {
const module = await import('./module.js');
module.doSomething();
} catch (err) {
console.error(err);
}
}
Dynamic Paths and Expressions
The power of dynamic import()
lies in its ability to accept dynamically generated paths, providing great flexibility for code splitting and conditional loading.
// Using a variable as the path
const lang = getUserLanguage();
import(`./locales/${lang}.js`)
.then(module => {
// Use the localized module
});
// Loading different modules based on conditions
async function getComponent() {
const componentName = await determineComponentToLoad();
return (await import(`./components/${componentName}.js`)).default;
}
Error Handling
Since dynamic import()
returns a Promise, error handling requires using either the Promise's catch
method or try/catch
syntax.
// Handling errors with Promise.catch
import('./non-existent-module.js')
.catch(err => {
console.error('Loading failed:', err);
});
// Using try/catch with async/await
async function loadModuleSafely() {
try {
const module = await import('./maybe-exists.js');
} catch (err) {
console.error('Module loading error:', err);
// Fall back to the default module
const defaultModule = await import('./default.js');
}
}
Integration with Bundlers like Webpack
Modern bundlers like Webpack can recognize dynamic import()
syntax and automatically perform code splitting.
// Webpack will automatically create a split point for the following code
const module = await import(/* webpackChunkName: "my-chunk" */ './module.js');
// Preloading hints
import(/* webpackPrefetch: true */ './some-module.js');
Practical Use Cases
- Route-level code splitting: Loading components per route in SPAs.
// Dynamic imports in React route configuration
const Home = React.lazy(() => import('./views/Home'));
const About = React.lazy(() => import('./views/About'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</Suspense>
);
}
- Conditional polyfill loading
if (!window.Promise) {
await import('promise-polyfill');
}
- Lazy loading heavy libraries
document.getElementById('chart-container').addEventListener('click', async () => {
const { Chart } = await import('heavy-chart-library');
new Chart(/* ... */);
});
Performance Optimization Tips
- Preloading critical modules: Use
<link rel="modulepreload">
or Webpack's magic comments.
import(/* webpackPreload: true */ './critical-module.js');
- Bulk loading: Use
Promise.all
to load multiple modules in parallel.
const [moduleA, moduleB] = await Promise.all([
import('./moduleA.js'),
import('./moduleB.js')
]);
- Caching loaded modules: Avoid duplicate loading.
const moduleCache = new Map();
async function getModule(name) {
if (moduleCache.has(name)) {
return moduleCache.get(name);
}
const module = await import(`./${name}.js`);
moduleCache.set(name, module);
return module;
}
Browser Compatibility and Polyfills
Dynamic import()
is widely supported in modern browsers, but older browsers may require polyfills or transpilation:
- Babel can support syntax transformation via the
@babel/plugin-syntax-dynamic-import
plugin. - Bundlers like Webpack implement dynamic loading logic in the output code.
- In unsupported environments, loaders like SystemJS can be used.
// Compatibility check
if (!('import' in window)) {
// Load a polyfill or fallback solution
await loadScript('dynamic-import-polyfill.js');
}
Handling Module Export Objects
The module object returned by dynamic import()
differs from static import
, so pay attention to the differences in export methods.
// module.js
export default function() {}
export const named = 'export';
// Using the module
const module = await import('./module.js');
module.default(); // Access default export
console.log(module.named); // Access named export
Advanced Patterns for Dynamic import
- Combining lazy loading and preloading
// Load on user interaction but preload in advance
function setupLazyButton() {
// Preload without execution
const modulePromise = import('./heavy-module.js');
document.getElementById('lazy-btn').addEventListener('click', async () => {
const module = await modulePromise;
module.run();
});
}
- Permission-based module loading
async function loadDashboard() {
const permissions = await fetchUserPermissions();
if (permissions.admin) {
await import('./admin-panel.js');
}
if (permissions.reports) {
await import('./reporting-tools.js');
}
}
- A/B testing module loading
async function loadVariant() {
const variant = Math.random() > 0.5 ? 'A' : 'B';
const module = await import(`./variants/${variant}.js`);
module.init();
}
Usage in Node.js
Dynamic import()
is also applicable in Node.js and is particularly useful for conditional module loading.
// Load different configurations based on the environment
async function getConfig() {
const env = process.env.NODE_ENV || 'development';
const { default: config } = await import(`./config.${env}.js`);
return config;
}
// Dynamically load ES modules (note: file extension must be .mjs or set type in package.json)
const fsPromises = await import('fs/promises');
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn