动态加载import()原理
ESmodule import() 原理
import() 函数是由TS39提出的一种动态加载模块的规范实现,其返回是一个 promise。在浏览器宿主环境中一个import()的参考实现如下:
function importModule(url) {
return new Promise((resolve, reject) => {
const script = document.createElement("script");
const tempGlobal = "__tempModuleLoadingVariable" + Math.random().toString(32).substring(2);
script.type = "module";
script.textContent = `import * as m from "${url}"; window.${tempGlobal} = m;`;
script.onload = () => {
resolve(window[tempGlobal]);
delete window[tempGlobal];
script.remove();
};
script.onerror = () => {
reject(new Error("Failed to load module script with URL " + url));
delete window[tempGlobal];
script.remove();
};
document.documentElement.appendChild(script);
});
}
<!DOCTYPE html>
<nav>
<a href="books.html" data-entry-module="books">Books</a>
<a href="movies.html" data-entry-module="movies">Movies</a>
<a href="video-games.html" data-entry-module="video-games">Video Games</a>
</nav>
<main>Content will load here!</main>
<script>
const main = document.querySelector("main");
for (const link of document.querySelectorAll("nav > a")) {
link.addEventListener("click", e => {
e.preventDefault();
import(`./section-modules/${link.dataset.entryModule}.js`)
.then(module => {
module.loadPageInto(main);
})
.catch(err => {
main.textContent = err.message;
});
});
}
</script>
与Webpack配合
当 Webpack 解析到该import()语法时,会自动进行代码分割。webpack 扫描源文件识别 import/export ,再根据识别结果重新打包组装生成新的文件,新生成的文件代码就已经按照浏览器能识别的方式重新组装了。
具体原理参考Webpack原理系列(一)动态import原理
使用 import() 执行简单的代码
首先,我们创建了所谓的 数据 URI。这种类型的 URI 协议是 data:。URI 的剩余部分中包含了所有资源的编码,而不是指向资源本身的地址。这样,数据 URI 就包含了一个完整的 ECMAScript 模块 —— 它的 content 类型是 text/javascript。 然后我们动态引入模块,于是代码被执行。
注意:这段代码只能在浏览器中运行
const js = `console.log('Hello everyone!');`;
const encodedJs = encodeURIComponent(js);
const dataUri = 'data:text/javascript;charset=utf-8,'
+ encodedJs;
import(dataUri);
// 输出:
// 'Hello everyone!'