<cite id="fzn17"></cite>
<var id="fzn17"></var><cite id="fzn17"><video id="fzn17"></video></cite>
<cite id="fzn17"></cite>
<var id="fzn17"></var>
<menuitem id="fzn17"><span id="fzn17"><thead id="fzn17"></thead></span></menuitem>
<cite id="fzn17"><span id="fzn17"><var id="fzn17"></var></span></cite><var id="fzn17"><span id="fzn17"><var id="fzn17"></var></span></var>
<var id="fzn17"></var>
<menuitem id="fzn17"></menuitem>
<cite id="fzn17"><video id="fzn17"></video></cite>
|
|
51CTO旗下网站
|
|
移动端

1.1.2 Node.js 的模块

《Node.js:来一打 C++ 扩展》第1章Node.js 的 C++ 扩展前驱知识储备,本章开始,笔者将逐步扩充读者对于 Node.js 的 C++ 模块开发的前驱知识储备,包括JavaScript 和 Node.js 的模块机制、包机制,Node.js 的源码依赖和对于开发环境所需要做的准备工作。本节为大家介绍Node.js 的模块。

作者:死月来源:电子工业出版社|2018-08-08 20:24

1.1.2 Node.js 的模块

Node.js 的应用通过入口文件之后,是由一个个模块组成的。通常一个模块是一个遵循CommonJS 规范书写的 JavaScript 源文件,也有可能是一个后缀为 *.node 的 C++ 模块二进制文件,这些文件通过 Node.js 中的 require() 函数被引入并使用。

使用 CommonJS 规范来作为 Node.js 的模块导出、引入机制,相当于把每个 JavaScript 文件或者模块当作一个不会污染全局的闭包,再配合 NPM2(Node.js 社区目前***的包管理系统)2.x 版本的嵌套式依赖方案,能非常优雅地实现某个依赖在一个项目中多版本共存(哪怕是不兼容的多个不同大版本)的情况。与比较适合前端开发的扁平化依赖方案 NPM 3.x 相比,2.x 更适合于 Node.js 应用的开发。

1. Node.js 模块寻径

对于 Node.js 来说,除了引入 CommonJS 规范,还对其做了一些附加的工作,比如模块寻径。

在 1.1.1 节中,笔者已经阐述过模块的标识,它是一个遵循小驼峰命名法的字符串,或者是一个以 "."、".." 开头的文件相对路径。但是在 Node.js 中,即使你不遵循小驼峰命名法的规范也是可以的,如 "chinese-random-name" 这个字符串在 Node.js 中也是一个合法的标识。除此之外,它还可以是一个不以 "."、".." 开头的相对路径,甚至?#37096;?#20197;是一个绝对路径。

上面几种命名对于 Node.js 来说,会采用几种不同的方法来寻找模块的路径。

(1) Node.js 核心模块

代码存在于 Node.js 源码库,并且将其 API 暴露给开发者的模块称为核心模块。这些核心模块都有自己的预留标识,当执行 require() 函数时传入的标识与某个 Node.js 核心模块相吻合时,该函数返回的是该核心模块的 API,如 "fs"、"net" 等。更多核心模块可以参考 Node.js官方文档。

(2) 文件模块

文件模块是指那些需要 Node.js 进行文件寻径获得的模块。下面会阐释寻径方式略微不同的两种模块——第三方模块和项目模块。

这两种模块虽然寻径方式有略微的不同,但是也有一些共通之处。

如果 Node.js 通过寻径?#39029;?#30340;路径代表的是一个目录,那么其会?#26469;?#23547;找该目录下的"index.js"、"index.json" 以及 "index.node" 文件。若存在上述任何一个字段,则立刻返回。

比如一个 JavaScript 文件路径是 /Users/biu/index.js,那么在执行 require("/Users/biu")的时候,该 JavaScript 文件会被加载。

不过寻?#19994;?#30340;如果是一个第三方模块目录,其目录下存在一个合法 package.json 文件的话,会在上述步骤之前解析 package.json 中的 "main" 字段。若该字段存在且合法,那么会直接加载该字段所指向的文件。

如当前目录下有这么一个目录结构,如图 1-2 所示。

如果在 a_program.js 中的代码是这样的:

  1. // a_program.js  
  2. const Biu = require("biu"); 

那么在模块寻径的时候会是 node_modules/biu 目录,该目录下同时存在 package.json 和 index.js,这个时候 Node.js 会先解析 package.json 文件。

这个时候如果 package.json 里面是这样的:

  1. // package.json 的部分源码  
  2. {  
  3. ...,  
  4. "main": "biu.js",  
  5. ...  

那么,这个时候执行该 require() 所得到的结果就应该是 node_modules/biu/biu.js 这个文件了。

(3) 第三方模块

除了上述的核心模块外,其他不是以 "/"、"./" 或者 "../" 开头的字符串作为标识的模块被称为第三方模块,这些模块通常以 Node.js 依赖包的形式存在。当 require() 函数传入的是第三方模块的标识时,则 Node.js 不仅仅在当前目录的 node_modules 目录下寻找文件名或者文件夹名与之相吻合的模块。这个?#23433;?#20165;仅”的意思如下:

① 当前文件目录的 node_modules 目录下;

② 若 ①没有符合的模块,则去当前文件目录的父目录的 node_modules 下;

③ 若没有符合的模块,则再往上一层目录的 node_modules;

④ 若没有符合的模块,重?#20648;郟?#30452;到寻?#19994;?#31526;合的模块或者根目录为止。

在?#19994;?#31526;合的模块之后,require() 函数就会返回?#19994;?#30340;模块所暴露的 API 了。

(4) 项目模块

在一个项目中执行 require() 来载入一个 "/"、"./" 或者 "../" 带头的模块就是项目模块了。它会加载文件路径相对于传入的标识的相对路径的模块,或者是绝对路径所指向的模块。由于通常加载 Node.js 模块的时候我们并不需要给其?#30001;?#21518;?#22909;?#36825;也是 CommonJS 中所规定的,因此 Node.js 在加载项目模块或者第三方模块的时候会枚举尝试后?#22909;?#23581;试的后?#22909;来?#20026; ".js"、".json" 和 ".node",其中 ".node" 就是 C++ 模块。

图 1-3 显示了一个项目模块的样例目录结构。

假设当前目录下的文件结构如图 1-3 所示,如果我们在 program.js 的代码是这样的:

  1. const CPP = require("./cpp_addon"); 

那么在模块加载寻径的时候,显而?#20934;?./cpp_addon 是不存在的,这个时候 Node.js 就会?#26469;?#21435;寻找 ./cpp_addon.js、./cpp_addon.json 和 ./cpp_addon.node,***会加载并返回 cpp_addon.node所暴露的 API。

2. 模块缓存

?#23548;?#19978;在 Node.js 运行中, 通常情况下一个包一旦被加载了, 那么在第二次执行require() 的时候就会在缓存中获取暴露的 API,而不会重新加载一遍该模块里面的代码再次返回。

如果有一个文件是 dog.js,代码如下:

  1. // dog.js  
  2. "use strict";  
  3. let boom = " 嘘,蛋花汤";  
  4. boom += " 在睡觉。🐶";  
  5. module.exports = {  
  6. "🐶": boom  
  7. }; 

而且在相同目录下有一个 entry.js,代码如下1:

  1. // entry.js  
  2. "use strict";  
  3. let ლ_ಠ 益ಠ_ლ = require("./dog");  
  4. console.log(ლ_ಠ 益ಠ_ლ);  
  5. let 蛋花汤 = require("./dog");  
  6. console.log( 蛋花汤); 

在entry.js 中执行 require() 时会通过寻径?#19994;?dog.js 并执行,暴露出来的 .. 变量值为" 嘘,蛋花汤在睡觉。..",也就是说输出会如下所示:

  1. $ node entry.js  
  2. { '🐶': ' 嘘,蛋花汤在睡觉。🐶' }  
  3. { '🐶': ' 嘘,蛋花汤在睡觉。🐶' } 

***句输出 { '..': ' 嘘,蛋花汤在睡觉。..' },理所当然;到了第二句的 require()时,由于 dog.js 已经被加载过了,Node.js 中会将其暴露的内容缓存到它的运行时中(其原理会在后续的章节中加以阐释),这个时候再执行 require() 就会直接返回内存中已加载好的module.exports,如下所示:

  1. {  
  2. "🐶": boom  

而不会出现重新执行一遍 dog.js,重新声明 boom 这个变量,更不会在原来的 boom 基础上再拼接一次 " 在睡觉。.." 以及出现 " 嘘,蛋花汤在睡觉。.. 在睡觉。.." 的荒谬结果。


?#19981;?#30340;朋友可以添加我们的微信账号:

51CTO读书频道二维码


51CTO读书会第9群:808517103

【责任编辑:book TEL:(010)68476606】

回书目   上一节   下一节
点赞 0
分享:
大家都在看
猜你?#19981;?/dt>

订阅专栏+更多

16招轻松掌握PPT技巧

16招轻松掌握PPT技巧

GET职场?#26377;?#25216;能
共16章 | 晒书包

289人订阅学习

20个局域网建设改造案例

20个局域网建设改造案例

网络搭建技巧
共20章 | 捷哥CCIE

645人订阅学习

WOT2019全球人工智能技术峰会

WOT2019全球人工智能技术峰会

通用技术、应用领域、企业赋能三大章节,13大技术专场,60+国内外一线人工智能精英大咖站台,分享人工智能的平台工具、算法模型、语音视觉等技术主题,助力人工智能落地。
共50章 | WOT峰会

0人订阅学习

读 书 +更多

数据库系统概念

本书是数据库系统方面的经典教材之一。国际上许多著名大学包括斯坦福大学、耶鲁大学、?#27599;?#33832;斯大学、?#30340;?#23572;大学、伊利诺伊大学、印度理工学...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊

51CTO服务号

51CTO播客

澳洲幸运5官方
<cite id="fzn17"></cite>
<var id="fzn17"></var><cite id="fzn17"><video id="fzn17"></video></cite>
<cite id="fzn17"></cite>
<var id="fzn17"></var>
<menuitem id="fzn17"><span id="fzn17"><thead id="fzn17"></thead></span></menuitem>
<cite id="fzn17"><span id="fzn17"><var id="fzn17"></var></span></cite><var id="fzn17"><span id="fzn17"><var id="fzn17"></var></span></var>
<var id="fzn17"></var>
<menuitem id="fzn17"></menuitem>
<cite id="fzn17"><video id="fzn17"></video></cite>
<cite id="fzn17"></cite>
<var id="fzn17"></var><cite id="fzn17"><video id="fzn17"></video></cite>
<cite id="fzn17"></cite>
<var id="fzn17"></var>
<menuitem id="fzn17"><span id="fzn17"><thead id="fzn17"></thead></span></menuitem>
<cite id="fzn17"><span id="fzn17"><var id="fzn17"></var></span></cite><var id="fzn17"><span id="fzn17"><var id="fzn17"></var></span></var>
<var id="fzn17"></var>
<menuitem id="fzn17"></menuitem>
<cite id="fzn17"><video id="fzn17"></video></cite>
pk10如何学会看走势 张柏芝艳照门 重庆时时实战技巧经验 哈尔滨酒店小姐招聘 幸运28最稳方法 昆明小姐上门特色服务 两面盘打法技巧 三公经费指什么 宝马5后排娱乐怎么用 数21游戏技巧