当前位置:网站首页>Do you really know esmodule
Do you really know esmodule
2022-07-28 13:57:00 【Maic】
We often come into contact with modules in projects , The most typical representative is esModule And commonjs, stay es6 And before that AMD Representative seajs,requirejs, Between the files loaded by the project module , How do we choose , For example, often because of a certain variable , We need to dynamically load a file , So you thought require('xxx'), We often use import Way to import routing components or files , wait . Therefore, it is necessary for us to really understand how to use it well , And use them correctly .
Here is the author's opinion on modular understand , I hope it can bring you some thinking and help in the actual project .
Text begins ...
About script The loaded IDS ,defer、async、module
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>module</title>
</head>
<body>
<div id="app"></div>
<script src="./js/2.js" defer></script>
<script src="./js/1.js" async></script>
<script src="./js/3.js">
console.log(' Synchronous loading ', 3)
</script>
</body>
</html>
// js/2.js
console.log('defer load ', 2);
// js/1.js
console.log('async Asynchronous loading does not guarantee sequence ', 1);
// js/3.js
console.log(' Synchronous loading ', 3)
We will find that the execution order is 3,1,2
defer And async It's asynchronous , And synchronously loaded 3, In the page, priority is given to . In the execution sequence , We can know the logo defer Yes, wait synchronous 3 And async Of 1 It is finally executed after execution .
To prove it , We are 1.js Add a code to
// 1.js
console.log(' There is no timer async', 1);
setTimeout(() => {
console.log(' With timer async, Asynchronous loading does not guarantee sequence ', 1);
}, 1000);
Finally, we found the order of printing , Synchronous loading 3,( There is no timer async)1、defer load 2、 With timer async, Asynchronous loading does not guarantee sequence 1
because 1.js Added a timer , In the event loop , It's a period of Macro task , We know that in the browser processing event loop , Synchronization task > Asynchronous task [ Micro task promise> Macro task setTimeout, Events, etc. ], stay 2.js of use defer Identify yourself as asynchronous , however 1.js There is a timer in ,2.js Actually, I waited 1.js performed , Reexecutive .
If I were in 2.js Timer is also added in
console.log(' There is no timer defer load ', 2);
setTimeout(() => {
console.log(' With timer defer load ', 2);
}, 1000);
We will find that the result is still the same
3.js Synchronous loading 3
1.js There is no timer async 1
2.js There is no timer defer load 2
1.js With timer async, Asynchronous loading does not guarantee sequence 1
2.js With timer defer load 2
It's not hard to find out defer Although the timer script in async In front of the identified script , however , Note that the two timers actually have a sequence , It has nothing to do with the order of the script
Both tasks are timers , All macro tasks , In the execution sequence of the script, the first timer will be put into the queue task first , The second timer will also be put in the queue , Follow FIFO , The first macro task (1.js With timer ) Advanced queue , then 2.js The timer enters the queue again , I'll do it later .
But notice , If the timer time is short, the priority is to enter the queue .
Okay , understand defer And async The difference between the , To sum up ,defer Will wait until other scripts are loaded , and async It's asynchronous , It doesn't have to be implemented first .
module
So let's see module
module The browser loads directly es6, We noticed that loading module What are the features in ?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>module</title>
</head>
<body>
<div id="app"></div>
<script src="./js/2.js" defer></script>
<script src="./js/1.js" async></script>
<script src="./js/3.js"></script>
<script type="module">
import userInfo, {cityList} from './js/4.js';
console.log(userInfo);
// { name: 'Maic', age: 18}
console.log(cityList);
console.log(this); // undefined
/*
[ {
value: ' Beijing ',
code: 1
},
{
value: ' Shanghai ',
code: 0
}
]
*/
</script>
</body>
</html>
stay js/4.js in , We can see that it can be used esModule Mode output of
export default {
name: 'Maic',
age: 18
}
const cityList = [
{
value: ' Beijing ',
code: 1
},
{
value: ' Shanghai ',
code: 0
}
]
export {
cityList
}
stay script use type="module" after , Internal top layer this It is no longer window Object , And the suffix cannot be omitted from the introduced external path , And the script automatically adopts strict mode .
es6 Modules and commonJS The difference between
Usually we are es6 modular , stay nodejs A large number of module codes in commonjs The way , Since it is useful in the project , So let's review the difference between them again
Reference resources module Load implementation [1] wrote
1、commonjs The output is a copy of the value , and es6 modular The output is a reference to a read-only value
2、commonjs It's loaded at run time , and es6 modular Is the output interface at compile time
3、commonjs Of require() It's synchronous loading , and es6 Of import xx from xxx Is asynchronous load , There is an independent module parsing stage
In addition, we also need to know commonjs Of require What is introduced is module.exports The object or attribute . and es6 Module is not an object , Its exposed interface is a static definition , It has been completed in the code parsing stage .
for instance ,commonjs
// 5.js
const userInfo = {
name: 'Maic',
age: 18
}
let count = 1;
const countAge = () => {
userInfo.age +=1;
count++;
console.log(`count:${count}`);
}
module.exports = {
userInfo,
countAge,
count
}
// 6.js
const {userInfo, countAge,count } = require('./5.js');
console.log(userInfo); // {name: 'Maic', age: 18}
countAge(); // count:2
console.log(userInfo); // {name: 'Maic', age: 19}
console.log(count); // 1
node 6.js It can be seen from the print , A raw output count, External call countAge It doesn't affect count Output value , But inside countAge What is printed is still current ++ After the value of .
If it is es6 modular , We can find out
const userInfo = {
name: 'Maic',
age: 18
}
let count = 1;
const countAge = () => {
userInfo.age +=1;
count++;
console.log('count', count);
}
export {
userInfo,
countAge,
count
}
Introduce... Into the page , We can find out
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>module</title>
</head>
<body>
<div id="app"></div>
...
<script type="module">
import userInfo, {cityList} from './js/4.js';
import {userInfo as nuseInfo, count, countAge} from './js/7.js'
console.log(userInfo, cityList);
console.log(this)
// { name: 'Maic', age: 18}
countAge();
console.log(nuseInfo, count);
// {name: 'Maic', age: 19} 2
</script>
</body>
</html>
We found that count The exported value changes in real time . Because it is a reference to a value .
Next, I have questions , For example, I have a tool function
function Utils() {
this.sum = 0;
this.add = function () {
this.sum += 1;
};
this.sub = function () {
this.sum-=1;
}
this.show = function () {
console.log(this.sum);
};
}
export new Utils;
This tool function , There will be references in many places , such as A,B,C... And other pages will introduce it , Then it will instantiate every time Utils?
Next, let's experiment
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>module</title>
</head>
<body>
<div id="app"></div>
...
<script type="module">
// A
import { utils } from './js/7.js'
utils.add();
console.log(utils);
</script>
<script type="module">
// B
import { utils } from './js/7.js';
console.log('sum=',utils.sum)
console.log(utils);
</script>
</body>
</html>
// 7.js
const userInfo = {
name: 'Maic',
age: 18
}
let count = 1;
const countAge = () => {
userInfo.age +=1;
count++;
console.log('count', count);
}
function Utils() {
this.sum = 0;
this.add = function () {
this.sum += 1;
};
this.sub = function () {
this.sum-=1;
}
this.show = function () {
console.log(this.sum);
};
}
const utils = new Utils;
export {
userInfo,
countAge,
count,
utils
};
We will find that in the A Call in the module utils.add() after , stay B Print in utils.sum yes 1, Then prove B Introduced utils And A It's the same .
What if I output only a constructor ? Look below
// 7.js
...
function Utils() {
this.sum = 0;
this.add = function () {
this.sum += 1;
};
this.sub = function () {
this.sum-=1;
}
this.show = function () {
console.log(this.sum);
};
}
const utils = new Utils;
const cutils = Utils;
export {
userInfo,
countAge,
count,
utils,
cutils
};
The page also introduces
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>module</title>
</head>
<body>
<div id="app"></div>
...
<script type="module">
// A
import {utils, cutils} from './js/7.js'
countAge();
console.log(nuseInfo, count);
utils.add();
new cutils().add();
console.log(utils)
</script>
<script type="module">
// B
import { utils, cutils } from './js/7.js';
console.log('sum=',utils.sum);
console.log(utils);
console.log('sum2=', new cutils().sum); // 0
</script>
</body>
</html>
We will find that A in new cutils().add() stay B in new cutils().sum) visit , Is still 0, So when a constructor is exported from a module , Each module corresponds to new Exported constructor Is to reopen a new memory space .
So we can come to the conclusion that , stay es6 The performance overhead of directly exporting instantiated objects in a module is smaller than that of directly exporting constructors .
CommonJS Module loading principle
Let's have a preliminary understanding CommonJS Loading
// A.js
module.exports = {
a:1
}
// B.js
const {a} = require('./A.js');
console.log(a) // 1
In execution require when , In fact, an object will be generated internally in memory ,require It's a nodejs A global function provided by the environment .
{
id: '...',
exports: { ... },
loaded: true,
...
}
Priority will be taken from the cache , If it is not in the cache, it is directly from exports The value of . For more details, please refer to this article require Source code interpretation [2]
in addition , We usually see the following code in the project
// A
exports.a = 1;
exports.b = 2;
// B
const a = require('./A.js');
console.log(a)// {a:1, b:2}
The above is equivalent to the following
// A.js
module.exports = {
a:1,
b:2
}
// B.js
const a = require('./A.js');
console.log(a); // {a:1,b:2}
So we can see require In fact, acquisition is module.exports Output {} Copy of a value of .
When exports.xxx when , actually require The obtained value result is still module.exports Copy of value . in other words , At run time , When using exports.xx In fact, time will quietly change into module.exports 了 .
summary
1、 Compare script,type Three modes introduced in defer、async、module Different .
2、 stay module Next , Browser support es modular ,import Mode loading module
3、commonjs It is loaded synchronously at runtime , And the exported value is a copy of the value , Can't do something like esMoule Do static analysis as well , and esModule Export is a value reference .
4、esModule Exported objects , Multiple file references will not be instantiated repeatedly , The object introduced by multiple files is the same object .
5、commonjs Loading principle , Priority will be obtained from the cache , And then from loader Load module
Reference material
[1] module Load implementation : https://www.wangdoc.com/es6/module-loader.html
[2] require Source code interpretation : https://www.ruanyifeng.com/blog/2015/05/require.html
边栏推荐
- Continuous (integration -- & gt; delivery -- & gt; deployment)
- JWT 登录认证 + Token 自动续期方案,写得太好了!
- 安全保障基于软件全生命周期-PSP应用
- 国产API管理工具Eolink太好用了,打造高效的研发利器
- Operator3 - design an operator
- Remember to use pdfbox once to parse PDF and obtain the key data of PDF
- 你真的了解esModule吗
- R语言使用lm函数构建多元回归模型(Multiple Linear Regression)、并根据模型系数写出回归方程、使用confint函数给出回归系数的95%置信区间
- The domestic API management tool eolink is very easy to use, creating an efficient research and development tool
- Poj3259 wormhole solution
猜你喜欢

Deploy application delivery services in kubernetes (Part 1)

Excellent performance! Oxford, Shanghai, AI Lab, Hong Kong University, Shangtang, and Tsinghua have joined forces to propose a language aware visual transformer for reference image segmentation! Open

记一次COOKIE的伪造登录

Strict mode -- let and const -- arrow function -- Deconstruction assignment -- string template symbol -- set and map -- generator function

Operator3 - design an operator

SLAM论文合集

Socket class understanding and learning about TCP character stream programming

【LVGL事件(Events)】事件在不同组件上的应用(一)

Algorithm --- different paths (kotlin)

No swagger, what do I use?
随机推荐
R language uses LM function to build linear regression model and subset function to specify subset of data set to build regression model (use floor function and length function to select the former pa
Socket类关于TCP字符流编程的理解学习
es6你用过哪些惊艳的写法
Analyzing the principle of DNS resolution in kubernetes cluster
Qt5 development from introduction to mastery -- the first overview
Excellent performance! Oxford, Shanghai, AI Lab, Hong Kong University, Shangtang, and Tsinghua have joined forces to propose a language aware visual transformer for reference image segmentation! Open
DXF读写:对齐尺寸标注文字居中、上方的位置计算
你真的了解esModule吗
算法---不同路径(Kotlin)
ES6 what amazing writing methods have you used
Algorithm --- different paths (kotlin)
R语言ggplot2可视化:使用ggpubr包的ggviolin函数可视化小提琴图、设置draw_quantiles参数添加指定分位数横线(例如,50%分位数、中位数)
30天刷题计划(三)
Li Kou sword finger offer 51. reverse order pairs in the array
Three men "running away" from high positions in the mobile phone factory
Continuous (integration -- & gt; delivery -- & gt; deployment)
R language uses dpois function to generate Poisson distribution density data and plot function to visualize Poisson distribution density data
Vite configuring path aliases in the project
Poj3259 wormhole solution
30 day question brushing training (I)