module的加载实现

1.浏览器加载

HTML网页中,浏览器通过使用<script>标签加载JavaScript脚本。是同步加载,执行完脚本才会继续向下渲染,会造成浏览器堵塞。

<script type="application/javascript />

<script>标签打开deferasync属性,脚本就会异步加载。渲染引擎遇到这个命令就开始下载外部脚本,但是不会等它下载和执行,而是直接执行后面的命令。
defer:要等整个压面渲染结束后,才会执行。按照页面出现顺序加载。
async:下载完就执行,不能保证按序加载。

<script src="path/to/myModule.js" defer />
<script src="path/to/myModule.js" async />

2. ES6加载

浏览器加载 ES6 模块,也使用<script>标签,但是要加入type="module"属性。是异步加载,等同于打开了<script>标签的defer属性。

<script type="module" src="./foo.js" />

3. ES6与CommonJS模块的差异

两大重大差异:

  1. commonJS模块输出的是一个值的拷贝,ES6模块输出的是值的引用; commonJS模块是运行时加载,ES6模块是编译时输出接口。
  2. commonJS加载的是一个对象(module.exports),该对象只有在脚本运行完才会执行。而ES6模块不是对象,它对外接口只是一种静态定义,在代码静态解析阶段就会生成。

CommonJS模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。

// lib.js
var counter = 3;
function incCounter() {
  counter++;
}
module.exports = {
  counter: counter,
  incCounter: incCounter,
};
// main.js
var mod = require('./lib');

console.log(mod.counter);  // 3
mod.incCounter();
console.log(mod.counter); // 3

上面代码说明,lib.js模块加载以后,它的内部变化就影响不到输出的mod.counter了。这是因为mod.counter是一个原始类型的值,会被缓存。除非写成一个函数,才能得到内部变动后的值。

ES6模块的运行机制与 CommonJS不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,ES6import有点像 Unix 系统的“符号连接”,原始值变了,import加载的值也会跟着变。因此,ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。

// lib.js
export let counter = 3;
export function incCounter() {
  counter++;
}

// main.js
import { counter, incCounter } from './lib';
console.log(counter); // 3
incCounter();
console.log(counter); // 4

3. Node.js加载

Node.js 要求 ES6 模块采用.mjs后缀文件名。也就是说,只要脚本文件里面使用import或者export命令,那么就必须采用.mjs后缀名。Node.js 遇到.mjs文件,就认为它是 ES6 模块,默认启用严格模式,不必在每个模块文件顶部指定"use strict"

如果不希望将后缀名改成.mjs,可以在项目的package.json文件中,指定type字段为module

{
   "type": "module"
}

如果这时还要使用CommonJS 模块,那么需要将 CommonJS 脚本的后缀名都改成.cjs。如果没有type字段,或者type字段为commonjs,则.js脚本会被解释成 CommonJS 模块。

总结为一句话:.mjs文件总是以 ES6 模块加载,.cjs文件总是以 CommonJS 模块加载,.js文件的加载取决于package.json里面type字段的设置。

注意,ES6 模块与 CommonJS 模块尽量不要混用。require命令不能加载.mjs文件,会报错,只有import命令才可以加载.mjs文件。反过来,.mjs文件里面也不能使用require命令,必须使用import

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WPF(Windows Presentation Foundation)是一种用于创建Windows桌面应用程序的开发框架,而Prism是一个用于帮助开发人员构建可扩展、模块化的WPF应用程序的框架。 在WPF Prism中,模块是应用程序的组成部分,每个模块都是相对独立、可重用且可扩展的。模块可以使用Prism框架提供的功能进行和管理。 模块的过程包括以下步骤: 1. 定义模块:首先,需要在应用程序中定义模块。模块通常包括一个模块类,该类实现了IModule接口,并在其中进行模块的初始化工作。 2. 配置模块目录:为了模块,需要指定模块所在的目录。可以在应用程序的配置文件中设置模块目录的路径。 3. 模块发现:Prism框架将会在指定的模块目录中查找模块,并获取模块的配置信息。 4. 模块:根据模块的配置信息,Prism框架将逐个模块。过程会创建模块的实例,并在应用程序中进行初始化。 5. 模块初始化:一旦模块被,Prism框架将调用模块的初始化方法,用于注册模块的服务、视图等。 通过这种方式,应用程序可以使用Prism框架来实现模块化的架构。模块可以根据需求进行动态和卸,以实现更好的应用程序可扩展性和维护性。 总结起来,WPF Prism模块的过程涉及定义模块、配置模块目录、模块发现、模块和模块初始化等步骤。通过这些步骤,开发人员可以构建出可扩展、模块化的WPF应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值