Deno 是一款基于 V8 引擎的 JavaScript/TypeScript 运行时,它提供了一些新的特性和安全机制,比如将网络请求和文件系统访问作为内置功能提供,同时也支持 ES 模块和 CommonJS 模块的加载。本文将深入探讨 Deno 的模块加载机制,帮助读者更好地理解和使用 Deno。
模块的基本概念
在 Deno 中,模块是一段代码,它可以被其他代码引用和复用。模块可以是一个单独的文件,也可以是由多个文件组成的一个包。模块可以使用关键字 import
和 export
来进行导入和导出。
举个例子,假设我们有一个名为 greeting.ts
的模块,它导出了一个函数 sayHello
:
export function sayHello(name: string): void { console.log(`Hello, ${name}!`); }
我们可以在其他模块中使用 import
来引入这个模块:
import { sayHello } from './greeting.ts'; sayHello('Deno');
在上面的代码中,我们使用相对路径 ./greeting.ts
指定了要引入的模块。这个路径是相对于当前模块的路径,Deno 会根据这个路径去查找并加载模块。
模块的加载
Deno 的模块加载机制是相对简单的,它遵循了标准的 ES 模块和 CommonJS 模块规范。当我们在一个模块中使用 import
引入另一个模块时,Deno 会按照以下步骤去查找和加载这个模块:
解析路径:Deno 会根据引入语句中的路径解析出真实的文件路径。如果路径是一个相对路径,则会相对于当前模块的路径进行解析。如果路径是一个绝对路径,则会从根目录开始进行解析。
缓存检查:Deno 会检查是否已经加载过该模块。如果已经加载过,则会直接返回缓存中的模块对象。
下载模块:如果模块没有被缓存,则会去下载该模块。Deno 使用 HTTP/HTTPS 协议下载模块,如果下载失败,则会抛出一个错误。
编译模块:Deno 会将下载下来的模块进行编译,并生成一个模块对象。模块对象包含了模块的导出和导入信息。
执行模块:Deno 会执行模块的代码,并将导入的模块对象传递给模块。
缓存模块:执行完毕后,Deno 会将该模块缓存起来,以便下次使用。
模块的解析
在上面的加载过程中,第一步是解析路径。Deno 的模块解析规则比较灵活,它支持以下几种路径格式:
相对路径:以
./
或../
开头的路径,表示相对于当前模块的路径。绝对路径:以
/
开头的路径,表示从根目录开始的路径。URL 路径:以
http://
、https://
、file://
或data:
开头的路径,表示一个 URL 地址或者一个 data URI。模块名路径:不以
./
、../
或/
开头的路径,表示一个模块名。
对于模块名路径,Deno 会根据以下规则进行解析:
首先,Deno 会检查该模块名是否已经被缓存。如果已经被缓存,则直接返回缓存中的模块对象。
如果模块名是一个内置模块名,比如
deno
、std
等,则会从内置模块中查找该模块,并返回模块对象。如果模块名以
https://
或http://
开头,则会从远程加载该模块。Deno 会发送一个 HTTP 请求去下载该模块,并将下载下来的代码进行编译和执行。如果模块名是一个相对路径,则会相对于当前模块的路径进行解析。
如果模块名是一个绝对路径,则会从根目录开始进行解析。
如果模块名是一个包名,则会先在当前模块的同级目录中查找该包。如果找不到,则会在父级目录中查找,直到找到为止。如果还是找不到,则会去
$HOME/.deno/deps
目录中查找该包。
模块的导入
在 Deno 中,我们可以使用 import
关键字来导入其他模块。import
关键字有以下几种用法:
- 导入默认导出:
import foo from './foo.ts';
在上面的代码中,我们使用 import
导入了一个默认导出。默认导出的值可以是任何类型,它可以是一个函数、一个对象、一个类等等。
- 导入命名导出:
import { foo, bar } from './baz.ts';
在上面的代码中,我们使用 import
导入了两个命名导出。命名导出需要在模块中使用 export
关键字进行导出。
- 导入所有命名导出:
import * as baz from './baz.ts';
在上面的代码中,我们使用 import
导入了一个模块中的所有命名导出。这种方式会将所有导出都封装到一个对象中,我们可以通过这个对象来访问导出的变量和函数。
模块的循环依赖
在开发过程中,我们可能会遇到模块之间的循环依赖问题。比如模块 A 依赖模块 B,而模块 B 又依赖模块 A。这种情况下,Deno 会抛出一个错误,提示循环依赖。
为了解决循环依赖问题,我们需要重新设计模块的结构。通常来说,我们可以将模块拆分成更小的模块,避免模块之间的相互依赖。
总结
Deno 的模块加载机制遵循了标准的 ES 模块和 CommonJS 模块规范,同时也支持了一些新的特性和安全机制。在开发过程中,我们需要深入了解 Deno 的模块加载机制,以便更好地使用和开发 Deno 应用。
本文介绍了 Deno 的模块基本概念、加载过程、解析规则和导入方式,同时也讨论了模块的循环依赖问题。希望本文能够对读者有所帮助,同时也欢迎读者在评论区留言,分享自己的经验和想法。
示例代码:https://github.com/denoland/deno_std/tree/main/examples
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/650d02cd95b1f8cacd6c2865