ES6之Module 的加载实现(3)

4.循环加载

“循环加载”(circular dependency)指的是,a脚本的执行依赖b脚本,而b脚本的执行又依赖a脚本

这里写图片描述

通常,“循环加载”表示存在强耦合,如果处理不好,还可能导致递归加载,使得程序无法执行,因此应该避免出现

但是实际上,这是很难避免的,尤其是依赖关系复杂的大项目,很容易出现a依赖b,b依赖c,c又依赖a这样的情况。这意味着,模块加载机制必须考虑“循环加载”的情况

对于JavaScript语言来说,目前最常见的两种模块格式CommonJS和ES6,处理“循环加载”的方法是不一样的,返回的结果也不一样

4.1CommonJS模块的加载原理

CommonJS的一个模块,就是一个脚本文件。require命令第一次加载该脚本,就会执行整个脚本,然后在内存生成一个对象

这里写图片描述

上面代码就是Node内部加载模块后生成的一个对象。该对象的id属性是模块名,exports属性是模块输出的各个接口,loaded属性是一个布尔值,表示该模块的脚本是否执行完毕。其他还有很多属性,这里都省略了

以后需要用到这个模块的时候,就会到exports属性上面取值。即使再次执行require命令,也不会再次执行该模块,而是到缓存之中取值。也就是说,CommonJS模块无论加载多少次,都只会在第一次加载时运行一次,以后再加载,就返回第一次运行的结果,除非手动清除系统缓存

4.2CommonJS模块的循环加载

CommonJS模块的重要特性是加载时执行,即脚本代码在require的时候,就会全部执行。一旦出现某个模块被”循环加载”,就只输出已经执行的部分,还未执行的部分不会输出

这里写图片描述

上面代码之中,a.js脚本先输出一个done变量,然后加载另一个脚本文件b.js。注意,此时a.js代码就停在这里,等待b.js执行完毕,再往下执行

再看b.js的代码
这里写图片描述

上面代码之中,b.js执行到第二行,就会去加载a.js,这时,就发生了“循环加载”。系统会去a.js模块对应对象的exports属性取值,可是因为a.js还没有执行完,从exports属性只能取回已经执行的部分,而不是最后的值

a.js已经执行的部分,只有一行
这里写图片描述

因此,对于b.js来说,它从a.js只输入一个变量done,值为false

然后,b.js接着往下执行,等到全部执行完毕,再把执行权交还给a.js。于是,a.js接着往下执行,直到执行完毕。我们写一个脚本main.js,验证这个过程
这里写图片描述

执行main.js,运行结果如下
这里写图片描述

上面的代码证明了两件事。一是,在b.js之中,a.js没有执行完毕,只执行了第一行。二是,main.js执行到第二行时,不会再次执行b.js,而是输出缓存的b.js的执行结果,即它的第四行

这里写图片描述

总之,CommonJS输入的是被输出值的拷贝,不是引用

4.3ES6模块的循环加载

ES6处理“循环加载”与CommonJS有本质的不同。ES6模块是动态引用,如果使用import从一个模块加载变量(即import foo from ‘foo’),那些变量不会被缓存,而是成为一个指向被加载模块的引用,需要开发者自己保证,真正取值的时候能够取到值

这里写图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/407537.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

oracle存储过程写法(一)

Create or Replace Procedure Proc_AppendRecords(nAppendCount int -- 要添加的记录条数)asbegindeclarenstart int;nend int;beginselect NVL(max(UserID),0) into nstart from T_Test_Checkbill;nend : nstart nAppendCount;while nstart < …

Vue之重命名组件

因为header本身是关键字&#xff0c;所以这里通过重命名的方式改为’v-header’

Struts2学习笔记1

一&#xff0e;下载struts2.0.1 http://struts.apache.org/downloads.html&#xff0c;下载struts-2.0.1-all.zip&#xff0c;这个压缩包中包括了开发struts2所需的struts2-core.jar核心包以及其他struts2所依赖的JAR文件&#xff0c;另外另一些struts2的演示样例程序以及一些H…

Vue路径的别名

这里给’components’赋予了一个地址&#xff0c;那么在程序中引入路径的时候’components’就直接可以代替路径’../src/components’

简单的单级下拉菜单实现

这里用纯CSS实现一个简单的单级下拉菜单&#xff0c;鼠标划过菜单标题时显示下拉菜单。 基本思路 在菜单处于光标之下时显示菜单&#xff0c;其余时候隐藏。这个过程首先得想到 :hover 伪类来实现&#xff0c;但是直接的利用伪类还不行&#xff0c;因为普通状态下菜单隐藏了&am…

C#里面的继承

举个例子&#xff1a;有一个基类RectangleEx1 classRectangleEx2 {3 privateint_x, _y, _w, _h;4 5 publicintx6 {7 get{ return_x; }8 set{ _x value; }9 }10 publicinty11 {12 get{ return_y; }13 set{ _y value; }14 }15 publicintw16 {17 get{ return_w; }18 set{ _w value…

Vue-Router的路由实例构造配置

可以通过在创建路由实例的时候传入不同的对象来选择不同的配置&#xff0c;这里的’linkActiveClass’代表的是给被激活的<router-link>添加一个叫做’active’的类名&#xff0c;然后我们就可以在css中给被激活标签设置不同的CSS了 其余的还有

WinForm UI设计与开发思路(转)

最近一年来一直在做WinForm相关的系统&#xff0c;对WinForm的UI设计有一些想法想和大家讨论&#xff08;主要是比较忙&#xff0c;所以很多只是设想&#xff0c;还没有开发实例&#xff09; 关于WinUI&#xff0c;理想的情形应该是外观比较cool&#xff0c;能给用户良好的使用…

Vue之父组件向子组件传递数据

1.创建子组件&#xff0c;在src/components/文件夹下新建一个Child.vue 2.Child.vue的中创建props&#xff0c;然后创建一个名为message的属性 3.在App.vue中注册Child组件&#xff0c;并在template中加入child标签&#xff0c;标签中添加message属性并赋值 4.我们依然可以对m…

Vue之实例的生命周期

Vue实例有一个完整的生命周期&#xff0c;也就是从开始创建、初始化数据、编译模板、挂载Dom、渲染→更新→渲染、卸载等一系列过程&#xff0c;我们称这是Vue的生命周期。通俗说就是Vue实例从创建到销毁的过程&#xff0c;就是生命周期 在Vue的整个生命周期中&#xff0c;它提…

windows遍历目录下所有文件

From: http://blog.csdn.net/benbon/article/details/1911230 在windows中遍历目录下的所有文件主要是使用FindFirstFile和FindNextFile通过递归调用实现的,类似于Linux的opendir和readdir。 在MSDN中&#xff0c;FindFirstFile的声明如下&#xff1a; HANDLE FindFirstFile( …

Vue之计算属性Computed

计算属性将被添加到Vue的实例中。计算属性内部的getter和setter函数内的this上下文将自动地绑定为Vue实例 不应该使用箭头函数来定义计算属性函数 (例如 aDouble: () > this.a * 2)。理由是箭头函数绑定了父级作用域的上下文&#xff0c;所以 this 将不会按照期望指向 Vue …

关于用display:table让元素居中的小结

让元素垂直居中有一种简单的方法:给需要居中的元素用一个父级包起来&#xff0c;并给父元素添加样式’display&#xff1a;table’,同时给这个父级设置好高度,再给需要居中的元素一个display&#xff1a;table-cell,vertical-align:middle;这样被设置的元素就可以做到垂直居中 …