目录
一、语法说明
二、适用场合
三、注意点
四、示例代码
五、效果
import
命令会被 JavaScript 引擎静态分析,先于模块内的其他语句执行(import
命令叫做“连接” binding 其实更合适)。
// 报错
if (x === 2) {
import MyModual from './myModual';
}
上面代码中,引擎处理import
语句是在编译时,这时不会去分析或执行if
语句,所以import
语句放在if
代码块之中毫无意义,因此会报句法错误,而不是执行时错误。也就是说,import
和export
命令只能在模块的顶层,不能在代码块之中(比如,在if
代码块之中,或在函数之中)。
这样的设计,固然有利于编译器提高效率,但也导致无法在运行时加载模块。在语法上,条件加载就不可能实现。如果import
命令要取代 Node 的require
方法,这就形成了一个障碍。因为require
是运行时加载模块,import
命令无法取代require
的动态加载功能。
const path = './' + fileName;
const myModual = require(path);
上面的语句就是动态加载,require
到底加载哪一个模块,只有运行时才知道。import
命令做不到这一点。
ES2020提案 引入import()
函数,支持动态加载模块。
import(specifier)
上面代码中,import
函数的参数specifier
,指定所要加载的模块的位置。import
命令能够接受什么参数,import()
函数就能接受什么参数,两者区别主要是后者为动态加载。
import()
返回一个 Promise 对象。下面是一个例子。
const main = document.querySelector('main');
import(`./section-modules/${someVariable}.js`)
.then(module => {
module.loadPageInto(main);
})
.catch(err => {
main.textContent = err.message;
});
import()
函数可以用在任何地方,不仅仅是模块,非模块的脚本也可以使用。它是运行时执行,也就是说,什么时候运行到这一句,就会加载指定的模块。另外,import()
函数与所加载的模块没有静态连接关系,这点也是与import
语句不相同。import()
类似于 Node.js 的require()
方法,区别主要是前者是异步加载,后者是同步加载。
由于import()
返回 Promise 对象,所以需要使用then()
方法指定处理函数。考虑到代码的清晰,更推荐使用await
命令。
async function renderWidget() {
const container = document.getElementById('widget');
if (container !== null) {
// 等同于
// import("./widget").then(widget => {
// widget.render(container);
// });
const widget = await import('./widget.js');
widget.render(container);
}
}
renderWidget();
上面示例中,await
命令后面就是使用import()
,对比then()
的写法明显更简洁易读。
下面是import()
的一些适用场合。
(1)按需加载。
import()
可以在需要的时候,再加载某个模块。
button.addEventListener('click', event => {
import('./dialogBox.js')
.then(dialogBox => {
dialogBox.open();
})
.catch(error => {
/* Error handling */
})
});
上面代码中,import()
方法放在click
事件的监听函数之中,只有用户点击了按钮,才会加载这个模块。
(2)条件加载
import()
可以放在if
代码块,根据不同的情况,加载不同的模块。
if (condition) {
import('moduleA').then(...);
} else {
import('moduleB').then(...);
}
上面代码中,如果满足条件,就加载模块 A,否则加载模块 B。
(3)动态的模块路径
import()
允许模块路径动态生成。
import(f())
.then(...);
上面代码中,根据函数f
的返回结果,加载不同的模块。
import()
加载模块成功以后,这个模块会作为一个对象,当作then
方法的参数。因此,可以使用对象解构赋值的语法,获取输出接口。
import('./myModule.js')
.then(({export1, export2}) => {
// ...·
});
上面代码中,export1
和export2
都是myModule.js
的输出接口,可以解构获得。
如果模块有default
输出接口,可以用参数直接获得。
import('./myModule.js')
.then(myModule => {
console.log(myModule.default);
});
上面的代码也可以使用具名输入的形式。
import('./myModule.js')
.then(({default: theDefault}) => {
console.log(theDefault);
});
如果想同时加载多个模块,可以采用下面的写法。
Promise.all([
import('./module1.js'),
import('./module2.js'),
import('./module3.js'),
])
.then(([module1, module2, module3]) => {
···
});
import()
也可以用在 async 函数之中。
async function main() {
const myModule = await import('./myModule.js');
const {export1, export2} = await import('./myModule.js');
const [module1, module2, module3] =
await Promise.all([
import('./module1.js'),
import('./module2.js'),
import('./module3.js'),
]);
}
main();
在项目中新建src/动态模块文件夹,在该文件夹下新建index.js和module/index.js文件。如下图:
let resdata = import('./module')
resdata.then(resModule => {
resModule.axiosfun().then(res => {
console.log(res)
})
})
let axiosfun = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("动态模块import()使用测试")
}, 6000);
})
}
let axios = axiosfun()
export {
axiosfun
}
源码地址;https://github.com/1t1824d/es6_module_class_promise_await_demo/tree/master