Dynamic Import - Tải module khi cần (ES2020)
import() dạng function cho phép **tải module động** (lazy loading) tại runtime, thay vì static import ở đầu file. Trả về Promise resolve thành module object.
Cú pháp
import('./module.js')
.then(module => { /* module.default, module.namedExport */ })
.catch(err => { /* handle error */ });
// Hoặc async/await
const module = await import('./module.js');
Ví dụ minh họa
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Dynamic Imports</title>
<style>
body { font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; }
.result { font-size: 18px; font-weight: 500; color: rebeccapurple; font-family: monospace; }
button { padding: 8px 16px; cursor: pointer; }
</style>
</head>
<body>
<h1>Dynamic Imports trong JavaScript</h1>
<div class="result"></div>
<button class="btn-demo">TẢI MODULE ĐỘNG</button>
<h3>Nhấn nút để động import module</h3>
<script>
const btn = document.querySelector(".btn-demo");
const resEle = document.querySelector(".result");
btn.addEventListener("click", loadModule);
async function loadModule() {
try {
// Dynamic import - trả về Promise
const module = await import("./sample.js");
// Truy cập default export
resEle.textContent = module.default() + "\n";
// Hoặc module.testImport() nếu named export
// Truy cập named export
resEle.textContent += module.tellTime();
} catch (err) {
resEle.textContent = "Lỗi tải module: " + err.message;
}
}
</script>
</body>
</html>
sample.js (Module được import động)
// sample.js
export default function testImport() {
return 'Module testImport đã được import động\n';
}
export function tellTime() {
return new Date().toLocaleString('vi-VN');
}
Use Cases (Trường hợp sử dụng)
1. Code Splitting / Lazy Loading (Phân chia code)
// Chỉ tải chart library khi user click xem biểu đồ
async function showChart() {
const { Chart } = await import('chart.js');
new Chart(ctx, config);
}
btnChart.addEventListener('click', showChart);
2. Conditional Import (Import có điều kiện)
async function loadPolyfill() {
if (!String.prototype.startsWith) {
await import('core-js/stable/string/starts-with');
}
// Polyfill đã load, có thể dùng startsWith()
}
3. Locale-based Import (i18n)
async function loadLocale(lang) {
const messages = await import(`./locales/${lang}.js`);
return messages.default;
}
// loadLocale('vi').then(setMessages);
4. Dynamic Import trong Node.js (CommonJS context)
// CommonJS file không dùng import static
const loadModule = async () => {
const { default: myFunc } = await import('./esm-module.js');
myFunc();
};
Import.meta - Metadata của module hiện tại
// Trong module
console.log(import.meta.url); // URL của file module hiện tại
console.log(import.meta.resolve('./other.js')); // Resolve URL (Stage 3)
// Dùng để load resource tương đối
async function loadJSON(relativePath) {
const url = new URL(relativePath, import.meta.url);
const response = await fetch(url);
return response.json();
}
Error Handling
try {
const module = await import('./optional-feature.js');
module.init();
} catch (err) {
if (err.code === 'ERR_MODULE_NOT_FOUND') {
console.log('Tính năng không khả dụng');
} else {
console.error('Lỗi tải module:', err);
}
}
Lưu ý
- Dynamic import **luôn trả về Promise** (async).
- Module được tải **chỉ một lần** (cached), gọi import() lại trả về cached module.
- Cần server hỗ trợ ES Modules (HTTP, không phải file://).
- Webpack/Rollup/Vite tự động code-split tại các điểm
import().