CommonJs
에 대해 이야기했습니다. 아직 읽지 않았다면 이 기사가 있는 컬럼을 찾아 학습할 수 있습니다. CommonJs
,如果还没有看,可以查找本文章所在的专栏进行学习。CommonJs
有很多优秀的特性,下面我们再简单的回顾一下:模块代码只在加载后运行;
模块只能加载一次;
模块可以请求加载其他模块;
支持循环依赖;
模块可以定义公共接口,其他模块可以基于这个公共接口观察和交互;
Es Module
的独特之处在于,既可以通过浏览器原生加载,也可以与第三方加载器和构建工具一起加载。Es module
模块的浏览器可以从顶级模块加载整个依赖图,且是异步完成。浏览器会解析入口模块,确定依赖,并发送对依赖模块的请求。这些文件通过网络返回后,浏览器就会解析它们的依赖,,如果这些二级依赖还没有加载,则会发送更多请求。Es Module
不仅借用了 CommonJs
和 AMD
的很多优秀特性,还增加了一些新行为:Es Module
默认在严格模式下执行;
Es Module
不共享全局命名空;
Es Module
顶级的 this
的值是 undefined
(常规脚本是window
);
模块中的 var
声明不会添加到 window
对象;
Es Module
是异步加载和执行的;
exports
和 import
。export
命令用于规定模块的对外接口,import
命令用于输入其他模块提供的功能。export const nickname = "moment"; export const address = "广州"; export const age = 18;
const nickname = "moment"; const address = "广州"; const age = 18; export { nickname, address, age };
export function foo(x, y) { return x + y; } export const obj = { nickname: "moment", address: "广州", age: 18, }; // 也可以写成这样的方式 function foo(x, y) { return x + y; } const obj = { nickname: "moment", address: "广州", age: 18, }; export { foo, obj };
export
输出的变量就是本来的名字,但是可以使用as
关键字重命名。const address = "广州"; const age = 18; export { nickname as name, address as where, age as old };
export default "foo"; export default { name: 'moment' } export default function foo(x,y) { return x+y } export { bar, foo as default };
if(true){ export {...}; }
export
必须提供对外的接口:// 1只是一个值,不是一个接口export 1// moment只是一个值为1的变量const moment = 1export moment// function和class的输出,也必须遵守这样的写法function foo(x, y) { return x+y }export foo复制代码
export
命令定义了模块的对外接口以后,其他js文件就可以通过 import
命令加载整个模块import {foo,age,nickname} from '模块标识符'
import
CommonJs
에는 뛰어난 기능이 많이 있습니다. 아래에서 간단히 살펴보겠습니다. 모듈 코드는 로딩 후에만 실행됩니다 ;
🎜🎜 모듈은 한 번만 로드될 수 있습니다. 🎜🎜🎜🎜 모듈은 다른 모듈을 로드하도록 요청할 수 있습니다. 🎜🎜🎜🎜 순환 종속성을 지원합니다. 🎜🎜🎜🎜 모듈은 이를 기반으로 관찰하고 상호 작용할 수 있습니다. 공용 인터페이스 ;🎜🎜🎜Es 모듈
은 브라우저를 통해 기본적으로 로드되거나 Third-Fi를 통해 로드될 수 있다는 점에서 고유합니다. 파티 로더는 빌드 도구와 함께 로드됩니다. 🎜🎜Es 모듈
모듈을 지원하는 브라우저는 최상위 모듈에서 전체 종속성 그래프를 비동기적으로 로드할 수 있습니다. 브라우저는 항목 모듈을 구문 분석하고, 종속성을 결정하고, 종속 모듈에 대한 요청을 보냅니다. 이러한 파일이 네트워크를 통해 반환된 후 브라우저는 해당 종속성을 해결하고 이러한 보조 종속성이 로드되지 않은 경우 추가 요청이 전송됩니다. 🎜🎜이 비동기 재귀 로딩 프로세스는 전체 애플리케이션의 종속성 그래프가 해결될 때까지 계속됩니다. 종속성 그래프가 구문 분석된 후 참조 프로그램은 공식적으로 모듈을 로드할 수 있습니다. 🎜🎜Es 모듈
은 CommonJs
및 AMD
에서 많은 뛰어난 기능을 빌릴 뿐만 아니라 몇 가지 새로운 동작도 추가합니다. 🎜🎜Es 모듈
은 기본적으로 엄격 모드에서 실행됩니다.🎜🎜🎜🎜Es 모듈
은 전역 네임스페이스를 공유하지 않습니다.🎜 🎜🎜 🎜Es 모듈
최상위 this
의 값은 정의되지 않음
입니다(일반 스크립트는 window
입니다). ; 🎜🎜🎜🎜모듈의 var
선언은 window
객체에 추가되지 않습니다. 🎜🎜🎜🎜Es 모듈
은 비동기적으로 로드되고 실행됩니다. ; 🎜🎜🎜exports
및 import
라는 두 가지 명령으로 구성됩니다. 🎜🎜export
명령은 모듈의 외부 인터페이스를 지정하는 데 사용되며, import
명령은 다른 모듈에서 제공하는 기능을 가져오는 데 사용됩니다. 🎜🎜// foo.js export default function foo(x, y) { return x + y; } export const bar = 777; export const baz = "moment"; // main.js import { default as foo, bar, baz } from "./foo.js"; import foo, { bar, baz } from "./foo.js"; import foo, * as FOO from "./foo.js";
import("./foo.js").then((module) => { const { default: foo, bar, baz } = module; console.log(foo); // [Function: foo] console.log(bar); // 777 console.log(baz); // moment});复制代码
import("./foo.js").then((module) => { const { default: foo, bar, baz } = module; console.log(foo); // [Function: foo] console.log(bar); // 777 console.log(baz); // moment });
export
로 출력되는 변수는 원래 이름이지만 as
키워드를 사용하여 이름을 바꿀 수 있습니다. 🎜🎜const p = new Promise((resolve, reject) => { resolve(777); });const result = await p;console.log(result); // 777正常输出
// 错误 import { 'b' + 'ar' } from './foo.js'; // 错误 let module = './foo.js'; import { bar } from module; // 错误 if (x === 1) { import { bar } from './foo.js'; } else { import { foo } from './foo.js'; }
<script></script><script></script>
export
외부 인터페이스를 제공해야 합니다: 🎜🎜<script> console.log("模块情况下的"); </script> <script></script> <script> console.log("正常 script标签"); </script>
export
명령을 사용하여 모듈의 외부 인터페이스를 정의한 후 다른 js 파일에서 import
를 통해 전체 모듈을 로드할 수 있습니다. command🎜🎜<script></script> <script></script> <script></script> <script></script> <script></script>
import
명령은 다른 모듈에서 가져올 변수 이름을 지정하는 중괄호를 허용하며, 변수 이름은 가져온 모듈의 외부 인터페이스 이름과 동일해야 합니다. 🎜🎜가져온 변수는 읽기 전용 인터페이스이므로 재할당할 수 없습니다. 객체인 경우 해당 객체의 속성을 재할당할 수 있습니다. 내보낸 모듈은 값을 수정할 수 있으며 가져온 변수도 이에 따라 변경됩니다. 🎜🎜🎜🎜🎜Assignment to constant variable
的类型错误。import
语句中同时取得它们。可以依次列出特定的标识符来取得,也可以使用 *
来取得:// foo.js export default function foo(x, y) { return x + y; } export const bar = 777; export const baz = "moment"; // main.js import { default as foo, bar, baz } from "./foo.js"; import foo, { bar, baz } from "./foo.js"; import foo, * as FOO from "./foo.js";
import
导入的模块是静态的,会使所有被导入的模块,在加载时就被编译(无法做到按需编译,降低首页加载速度)。有些场景中,你可能希望根据条件导入模块或者按需导入模块,这时你可以使用动态导入代替静态导入。import
可以像调用函数一样来动态的导入模块。以这种方式调用,将返回一个 promise
。import("./foo.js").then((module) => { const { default: foo, bar, baz } = module; console.log(foo); // [Function: foo] console.log(bar); // 777 console.log(baz); // moment});复制代码
await
必须在带有 async
的异步函数中使用,否则会报错:import("./foo.js").then((module) => { const { default: foo, bar, baz } = module; console.log(foo); // [Function: foo] console.log(bar); // 777 console.log(baz); // moment });
Top-level await
:const p = new Promise((resolve, reject) => { resolve(777); });const result = await p;console.log(result); // 777正常输出
import
是静态执行,所以不能使用表达式和变量,这些只有在运行时才能得到结果的语法结构。// 错误 import { 'b' + 'ar' } from './foo.js'; // 错误 let module = './foo.js'; import { bar } from module; // 错误 if (x === 1) { import { bar } from './foo.js'; } else { import { foo } from './foo.js'; }
type
属性设置为 module
用来告知浏览器将 script
标签视为模块。<script></script><script></script>
defer
的方式延迟你的 nomodule
脚本:<script> console.log("模块情况下的"); </script> <script></script> <script> console.log("正常 script标签"); </script>
nomodule
脚本会被执行多次,而模块只会被执行一次:<script></script> <script></script> <script></script> <script></script> <script></script>
nomodule
脚本会阻塞 HTML
解析。你可以通过添加 defer
属性来解决此问题,该属性是等到 HTML
解析完成之后才执行。defer
및 async
는 선택적 속성이며 nomodule
스크립트에서 defer code 아래에서 둘 중 하나만 선택할 수 있습니다. >는 <code>HTML
이 구문 분석될 때까지 현재 스크립트를 구문 분석하지 않으며, async
는 HTML
를 차단하지 않고 HTML
와 병렬로 구문 분석합니다. > 코드> 구문 분석의 경우 모듈 스크립트는 async
속성을 지정할 수 있지만 기본적으로 모듈이 지연되므로 defer
에는 유효하지 않습니다. defer
和 async
是一个可选属性,他们只可以选择其中一个,在 nomodule
脚本下,defer
等到 HTML
解析完才会解析当前脚本,而 async
会和 HTML
并行解析,不会阻塞 HTML
的解析,模块脚本可以指定 async
属性,但对于 defer
无效,因为模块默认就是延迟的。
async
属性,模块脚本及其所有依赖项将于解析并行获取,并且模块脚本将在它可用时进行立即执行。Es Module
模块之前,必须先了解 Es Module
与 Commonjs
完全不同,它们有三个完全不同:CommonJS
模块输出的是一个值的拷贝,Es Module
输出的是值的引用;CommonJS
模块是运行时加载,Es Module
是编译时输出接口。CommonJS
模块的 require()
是同步加载模块,ES6 模块的import
命令是异步加载,有一个独立的模块依赖的解析阶段。CommonJS
加载的是一个对象(即module.exports
属性),该对象只有在脚本运行完才会生成。而 Es Module
不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。Commonjs
输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。具体可以看上一篇写的文章。Es Module
的运行机制与 CommonJS
不一样。JS引擎
对脚本静态分析的时候,遇到模块加载命令import
,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,import
就是一个连接管道,原始值变了,import
加载的值也会跟着变。因此,Es Module
是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。Module Record
) 封装了关于单个模块(当前模块)的导入和导出的结构信息。此信息用于链接连接模块集的导入和导出。一个模块记录包括四个字段,它们只在执行模块时使用。其中这四个字段分别是:Realm
: 创建当前模块的作用域;Environment
:模块的顶层绑定的环境记录,该字段在模块被链接时设置;Namespace
:模块命名空间对象是模块命名空间外来对象,它提供对模块导出绑定的基于运行时属性的访问。模块命名空间对象没有构造函数;HostDefined
:字段保留,以按 host environments
使用,需要将附加信息与模块关联。import
async
속성이 있으면 모듈 스크립트와 모든 종속성이 병렬로 구문 분석되어 가져오고, 모듈 스크립트가 사용 가능한 경우 즉시 실행됩니다. Es 모듈과 Commonjs의 차이점
Es 모듈
모듈을 논의하기 전에 먼저Es를 이해해야 합니다. 모듈
Commonjs
와 완전히 다르며 세 가지 완전히 다른 차이점이 있습니다. 🎜🎜🎜
🎜🎜두 번째 차이점은CommonJS
모듈은Es 값의 복사본을 출력합니다. 모듈
출력은 값에 대한 참조입니다. 🎜🎜CommonJS
모듈은 런타임에 로드되고Es 모듈
은 컴파일 타임 출력 인터페이스입니다. 🎜🎜CommonJS
모듈의require()
는 모듈을 동기적으로 로드하는 반면, ES6 모듈의import
명령은 비동기적으로 로드하며 독립적인 모듈 종속성 구문 분석 단계를 갖습니다. 🎜CommonJS
가 스크립트가 생성된 후에만 로드되는 객체(예:module.exports
속성)를 로드하기 때문입니다. . 그리고Es 모듈
은 객체가 아닙니다. 외부 인터페이스는 코드의 정적 분석 단계에서 생성되는 정적 정의일 뿐입니다. 🎜🎜Commonjs
는 값의 복사본을 출력합니다. 즉, 값이 출력되면 모듈 내의 변경 사항이 값에 영향을 미치지 않습니다. 자세한 내용은 이전 글을 참고해주세요. 🎜🎜Es 모듈
의 작동 메커니즘은CommonJS
의 작동 메커니즘과 다릅니다.JS 엔진
이 스크립트를 정적으로 분석할 때 모듈 로딩 명령import
가 발생하면 읽기 전용 참조를 생성합니다. 스크립트가 실제로 실행되면 이 읽기 전용 참조를 기반으로 로드된 모듈에서 값이 검색됩니다. 즉,import
는 연결 파이프입니다. 원래 값이 변경되면import
에 의해 로드된 값도 그에 따라 변경됩니다. 따라서Es 모듈
은 동적 참조이며 값을 캐시하지 않습니다. 모듈의 변수는 해당 변수가 위치한 모듈에 바인딩됩니다. 🎜🎜Es 모듈 작동 원리 관련 개념
🎜🎜작동 원리를 배우기 전에 관련 개념을 이해하는 것이 좋습니다. 🎜🎜모듈 기록
🎜🎜모듈 기록(모듈 기록
)은 단일 모듈(현재 모듈) 정보의 가져오기 및 내보내기 구조를 캡슐화합니다. . 이 정보는 연결 모듈 세트의 가져오기 및 내보내기를 연결하는 데 사용됩니다. 모듈 레코드는 모듈을 실행할 때만 사용되는 4개의 필드로 구성됩니다. 네 가지 필드는 다음과 같습니다. 🎜🎜🎜
Realm
: 현재 모듈의 범위를 생성합니다. 🎜🎜Environment
: 모듈의 최상위 바인딩 환경 레코드입니다. 이 필드는 모듈이 연결될 때 설정됩니다. 🎜🎜네임스페이스
: 모듈 네임스페이스 개체는 모듈의 내보내기 바인딩에 대한 런타임 속성 기반 액세스를 제공하는 모듈 네임스페이스 외부 개체입니다. 모듈 네임스페이스 객체에는 생성자가 없습니다. 🎜🎜HostDefined
: 필드는호스트 환경
에서 사용하도록 예약되어 있으며 모듈과 연결하려면 추가 정보가 필요합니다. 🎜모듈 환경 레코드
🎜🎜모듈 환경 레코드는 ECMAScript 모듈의 외부 범위를 나타내는 데 사용되는 선언적 환경 레코드입니다. 일반적인 변경 가능 및 불변 바인딩 외에도 모듈 환경 레코드는 다른 환경 레코드 간접 액세스에 존재하는 대상에 대한 바인딩을 제공하는 변경 불가능한import
바인딩도 제공합니다. 🎜🎜🎜🎜불변 바인딩은 현재 모듈이 다른 모듈을 도입하고, 도입된 변수를 수정할 수 없다는 것을 의미합니다. 이는 모듈의 고유한 불변 바인딩입니다. 🎜
js
파일을 검색하고 인터넷을 통해 다운로드한 후 모듈 파일을 모듈 레코드
로 구문 분석합니다. Construction
),根据地址查找 js
文件,通过网络下载,并且解析模块文件为 Module Record
;Instantiation
),对模块进行实例化,并且分配内存空间,解析模块的导入和导出语句,把模块指向对应的内存地址;Evaluation
),运行代码,计算值,并且将值填充到内存地址中;loader
负责对模块进行寻址及下载。首先我们修改一个入口文件,这在 HTML
中通常是一个 <script type="module"></script>
的标签来表示一个模块文件。import
语句声明,在 import
声明语句中有一个 模块声明标识符(ModuleSpecifier
),这告诉 loader
怎么查找下一个模块的地址。模块记录(Module Record)
,而每一个 模块记录
包含了 JavaScript代码
、执行上下文
、ImportEntries
、LocalExportEntries
、IndirectExportEntries
、StarExportEntries
。其中 ImportEntries
值是一个 ImportEntry Records
类型,而 LocalExportEntries
、IndirectExportEntries
、StarExportEntries
是一个 ExportEntry Records
类型。ImportEntry Records
包含三个字段 ModuleRequest
、ImportName
、LocalName
;ModuleSpecifier
);ModuleRequest
模块标识符的模块导出所需绑定的名称。值 namespace-object
表示导入请求是针对目标模块的命名空间对象的;import
导入的 ImportEntry Records
인스턴스화
), 모듈을 인스턴스화하고, 메모리 공간을 할당하고, 모듈의 가져오기 및 내보내기 문을 구문 분석하고, 모듈을 해당 메모리 주소로 지정합니다.
|
모듈은 import 문을 통해 계속 선언됩니다. import 에 모듈 선언 식별자(ModuleSpecifier )가 있습니다. 이 문장은 loader 에게 다음 모듈의 주소를 찾는 방법을 알려줍니다. |
|
각 모듈 식별 번호는 |
---|---|---|---|
A ImportEntry Records 에는 ModuleRequest , ImportName, <code>LocalName ;
|
ModuleRequest: 모듈 식별자(ModuleSpecifier ); |
ImportName: ModuleRequest 에 의한 모듈 식별자 모듈 필요한 바인딩의 이름을 내보냅니다. namespace-object 값은 가져오기 요청이 대상 모듈의 네임스페이스 개체에 대한 것임을 나타냅니다. |
|
자세한 내용은 아래 사진을 참고해주세요: | 다음 표에는 | ||
모듈 식별자(모듈 요청) | ImportName(ImportName) | LocalName(LocalName) | |
import "react"에서 반응; | "react" | "default" | "React" |
ExportEntry Records
에는 ExportName
, ModuleRequest
, ImportName
, LocalName 4개의 필드가 포함되어 있습니다. <code>ImportEntry Records
와 다른 에는 추가 ExportName
이 있습니다. ExportEntry Records
包含四个字段 ExportName
、ModuleRequest
、ImportName
、LocalName
,和 ImportEntry Records
不同的是多了一个 ExportName
。下面这张表记录了使用 export
导出的 ExportEntry Records
ExportName: 이 모듈은 내보낼 때 이름을 바인딩하는 데 사용됩니다.
Export 문 | 내보내기 이름 | 모듈 식별자 | 가져오기 이름 | |
---|---|---|---|---|
export var v; | "v" | null | null | |
기본 함수 f() 내보내기 {} | "default" | null | null | |
기본 함수 내보내기() {} | "default" | null | null" | default|
기본값 42 내보내기; | "default" | null | null" | default|
export {x}; | "x" | null | null | |
{v를 x로 내보내기}; | "x" | null | null | |
"mod"에서 {x} 내보내기; | "x" | "mod " | "x" | |
export {v as x} from "mod"; | "x" | "mod" | "v" | |
export * from "mod"; | null | "mod" | all-but-default | |
"mod"에서 ns로 * 내보내기; | "ns | "mod" | all |
주제로 돌아가기
현재 모듈 레코드
를 구문 분석한 후에만 현재 모듈이 어떤 하위 모듈에 의존하는지 알 수 있으며 그런 다음 하위 해결
이 필요합니다. 모듈, 하위 모듈을 얻은 다음 하위 모듈을 구문 분석하고 이 해결 과정을 계속해서 가져오기 -> 결과는 아래 그림과 같습니다. https://img.php.cn /upload/article/000/000/020/199ce9bded58feb1ab4aa3e006ef5934-7.png" alt="한 기사로 es6 모듈화를 완전히 이해하세요." loading="lazy"/>Module Record
之后,才能知道当前模块依赖的是那些子模块,然后你需要 resolve
子模块,获取子模块,再解析子模块,不断的循环这个流程 resolving -> fetching -> parsing,结果如下图所示:
静态分析
,不会运行JavaScript代码,只会识别 export
和 import
关键字,所以说不能在非全局作用域下使用 import
,动态导入除外。loader
使用 Module Map
对全局的 MOdule Record
进行追踪、缓存这样就可以保证模块只被 fetch
一次,每个全局作用域中会有一个独立的 Module Map。MOdule Map 是由一个 URL 记录和一个字符串组成的key/value的映射对象。URL记录是获取模块的请求URL,字符串指示模块的类型(例如。“javascript”)。模块映射的值要么是模块脚本,null(用于表示失败的获取),要么是占位符值“fetching(获取中)”。
Module Record
被解析完后,接下来 JS 引擎需要把所有模块进行链接。JS 引擎以入口文件的 Module Record
作为起点,以深度优先的顺序去递归链接模块,为每个 Module Record
创建一个 Module Environment Record
,用于管理 Module Record
中的变量。Module Environment Record
中有一个 Binding
,这个是用来存放 Module Record
导出的变量,如上图所示,在该模块 main.js
处导出了一个 count
的变量,在 Module Environment Record
中的 Binding
就会有一个 count
,在这个时候,就相当于 V8
的编译阶段,创建一个模块实例对象,添加相对应的属性和方法,此时值为 undefined
或者 null
,为其分配内存空间。count.js
中使用了 import
关键字对 main.js
进行导入,而 count.js
的 import
和 main.js
的 export
정적 분석
은 JavaScript 코드를 실행하지 않으며 export
및 import
키워드만 인식하므로 import
는 불가능합니다. 가져오기를 제외하고 비전역 범위에서 동적으로 사용됩니다. 여러 파일이 동시에 하나의 파일에 의존하는 경우 무한 루프가 발생합니까? 대답은 '아니요'입니다.
loader
는 모듈 맵
을 사용하여 전역 MOdule 레코드
를 추적하고 캐시하여 모듈이 가져오기
>만 수행되도록 합니다. 일단 각 전역 범위에 독립적인 모듈 맵이 있게 됩니다. 🎜🎜🎜MOdule Map은 URL 레코드와 문자열로 구성된 키/값 매핑 개체입니다. URL 레코드는 모듈을 가져오기 위한 요청 URL이며, 모듈 유형을 나타내는 문자열(예: "javascript")입니다. 모듈 맵의 값은 모듈 스크립트, null(가져오기 실패를 나타내는 데 사용됨) 또는 자리 표시자 값 "가져오기"입니다. 🎜🎜🎜
모듈 레코드
가 구문 분석된 후 JS 엔진은 모든 모듈 링크를 처리해야 합니다. JS 엔진은 항목 파일의 모듈 레코드
를 시작점으로 사용하여 깊이 우선 순서로 모듈을 재귀적으로 연결하고 각 모듈에 대한 <code>모듈 환경 레코드
를 생성합니다. 레코드.code>, 모듈 레코드
에서 변수를 관리하는 데 사용됩니다. 🎜🎜🎜🎜🎜모듈 환경 레코드
에는 위 그림과 같이 모듈 레코드
에서 내보낸 변수를 저장하는 데 사용되는 바인딩
이 있습니다. 모듈 main.js
는 모듈 환경 레코드
의 바인딩
에서 찾을 수 있는 count
변수를 내보냅니다. code>count는 현재 V8
의 컴파일 단계와 동일하며, 모듈 인스턴스 객체를 생성하고 해당 속성과 메서드를 추가합니다. 이때 값은 입니다. 정의되지 않음
또는 null
인 경우 메모리 공간을 할당하세요. 🎜🎜import
키워드는 하위 모듈 count.js
에서 main.js
를 가져오는 데 사용되며 count.js는
의 import
변수와 main.js
의 export
변수가 가리키는 메모리 위치가 동일하므로 상위 및 하위 모듈 관계가 연결됩니다. 아래 그림과 같이:🎜🎜🎜🎜🎜export
导出的为父模块,import
引入的为子模块,父模块可以对变量进行修改,具有读写权限,而子模块只有读权限。Es Module
中有5种状态,分别为 unlinked
、linking
、linked
、evaluating
和 evaluated
,用循环模块记录(Cyclic Module Records
)的 Status
字段来表示,正是通过这个字段来判断模块是否被执行过,每个模块只执行一次。这也是为什么会使用 Module Map
来进行全局缓存 Module Record
的原因了,如果一个模块的状态为 evaluated
,那么下次执行则会自动跳过,从而包装一个模块只会执行一次。 Es Module
采用 深度优先
的方法对模块图进行遍历,每个模块只执行一次,这也就避免了死循环的情况了。深度优先搜索算法(英语:Depth-First-Search,DFS)是一种用于遍历或搜索树或图的算法。这个算法会尽可能深地搜索树的分支。当节点v的所在边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。
// main.js import { bar } from "./bar.js"; export const main = "main"; console.log("main"); // foo.js import { main } from "./main.js"; export const foo = "foo"; console.log("foo"); // bar.js import { foo } from "./foo.js"; export const bar = "bar"; console.log("bar");
node
运行 main.js
,得出以下结果:위 내용은 한 기사로 es6 모듈화를 완전히 이해하세요.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!