设为首页 收藏本站
查看: 755|回复: 0

[经验分享] nodeJS入门例子一—模块(Modules)

[复制链接]

尚未签到

发表于 2017-2-22 08:14:45 | 显示全部楼层 |阅读模式
模块(Modules)

周期(Cycles)

核心模块(Core Modules)

文件模块( File Modules)

从节点模块(node_modules)文件夹加在

文件夹作为模块

缓存(Caching)

模块缓存说明

module.exports

module.require

其他...

从全局文件夹加载

访问主模块
  附录:包管理技巧
  


Modules(模块)
  Node有一个简单的模块加载系统。在Node中,文件和模块 inone-to-one 通讯。如下例子,foo.js在相同目录下加载模块circle.js

  

  foo.js内容如下:


var circle = require('./circle.js');
console.log( 'The area of a circle of radius 4 is '
+ circle.area(4));
  circle.js内容如下:


var PI = Math.PI;
exports.area = function (r) {
return PI * r * r;
};
exports.circumference = function (r) {
return 2 * PI * r;
};
  circle.js模块有两个输出函数area() 和 circumference()。为输出对象, 添加详细的输出对象(exports object)。
  模块的局部变量是私有的。在这个例子中标量PI是circle.js私有的。

  


Cycles (周期)
  当互相加载时,当期返回时一个模块可能不会执行完成

  考虑这种情况:

  

  a.js:

console.log('a starting');
exports.done = false;
var b = require('./b.js');
console.log('in a, b.done = %j', b.done);
exports.done = true;
console.log('a done');
  b.js:

console.log('b starting');
exports.done = false;
var a = require('./a.js');
console.log('in b, a.done = %j', a.done);
exports.done = true;
console.log('b done');
  main.js:

console.log('main starting');
var a = require('./a.js');
var b = require('./b.js');
console.log('in main, a.done=%j, b.done=%j', a.done, b.done);
当main.js家在a.js时,a.js加载b.js,此时b.js尝试加载a.js。为了预防无限循环拷贝未完成的返回给b.js的a.js的输出对象。
b.js完成加载,并且将其输出对象提供给a.js模块

  

  此时main.js完成加载两个模块。其输出如下


$ node main.js
main starting
a starting
b starting
in b, a.done = false
b done
in a, b.done = true
a done
in main, a.done=true, b.done=true
如果在你程序中有循环依赖模块中,确保规划中间的关系。


Core Modules (核心模块)
  Node有几个编译成二进制的模块。这些模块在NODE文档中有详尽的描述。
  核心模块的定义在node的源码文件夹lib/文件夹中。
  

  如果require()鉴定通过,核心模块将优先加载。例如,require("http")将总是返回建立的http模块,即使有一个文件的名字。



File Modules (文件模块)
  如果执行的文件名没有找到,node将尝试加载请求后缀为.js、.json和.node 文件名相同的文件。.js文件解析成JavaScript的文本文件,
  .json文件解析成JSON文本文件,.node文件解析成用dlopen加载的编译的附加模块


模块前缀为"/"是一个文件的绝对路径。如:require('/home/marco/foo.js')将加载在/home/marco/foo.js下的文件。  模块前缀为“./”是一个调用require()加载的文件的相对路径。也就是说,用require('./circle')加载时找到此文件,circle.js必须要和foo.js在同一目录下面。
  没有'/'或者'./'前缀表示文件时,模块是核心模块或者是从node_modules文件夹里加载。

  


从`node_modules`文件夹中加载
  如果通过require()标识模块不是本地模块,并且没有以'/'、'../'或者'./'开头,node从当前模块的父目录开始,添加/node_modules,并尝试从本地加载模块。

  如果没有在这里找到,将会从父文件夹查找,直到达到最顶层文件夹。

  例如,如果 '/home/ry/projects/foo.js'调用require('bar.js'),node将以以下本地路径查找,顺序如下:



  • /home/ry/projects/node_modules/bar.js
  • /home/ry/node_modules/bar.js
  • /home/node_modules/bar.js
  • /node_modules/bar.js
  这允许程序设置依赖的本地化,所以不会引起冲突。

  


文件夹作为模块(Folders as Modules )
  这非常方便地组织程序和libraries 到一个独立的目录下,并且对library提供一个简单的入口点。在某个文件夹有三种方式作为参数传递给require()。

  第一种在文件夹的根路径下(在main 模块中申明描述的)创建一个package.json文件。一个package.json文件的例子如下:

  


{ "name" : "some-library",
"main" : "./lib/some-library.js" }
如果实在 ./some-library的文件夹下,require('./some-library')尝试着加载。./some-library/lib/some-library.js。
这是package.json文件的Node意识扩展。
如果在目录中没有package.json存在,node将尝试着加载文件夹外的index.js或者index.node文件。例如:上例子中没有package.json文件,
然后 require('./some-library')尝试着加载


  • ./some-library/index.js
  • ./some-library/index.node




缓存 (Caching )
  当第一次加载时模块都将被缓存。也就是说如果在相同的文件中,每次调用 require('foo')将精确地获取返回的相同的对象,

  多次调用require("foo")可能不会引起多次调用。这是一个很只要的特征。随之,部分完成对象可以返回,因此即时互调时都可依靠加载来传递。
  如果想要模块代码多次调用,需要外置(export)一个函数,并调用此函数。



模块缓存说明(Module Caching Caveats )
  模块的缓存基于决定的文件名。因为模块基于调用模块本地解析可能使用不同的文件名(从node_modules文件夹中加载)。如果不同的文件解析,不保证require("foo")将会总是返回准确相同的对象。


模块外置接口(module.exports )
  exports对象是通过系统模块创建的。有时这不是合要求的,很多时候需要一些类的实体。为了做此分配,描述module.exports的export对象。例如建立一个叫a.js的模块(module)。

  


var EventEmitter = require('events').EventEmitter;
module.exports = new EventEmitter();
//一段时间后从这个模块本身触发'ready'事件。
setTimeout(function() {
module.exports.emit('ready');
}, 1000);
在另外一个文件中,可以这么做:

  


var a = require('./a');
a.on('ready', function() {
console.log('module a is ready');
});
注意分配module.exports必须立即完成。不能在任何回调函数中完成。如下就不能生效:

  

  x.js:

setTimeout(function() {
module.exports = { a: "hello" };
}, 0);
  y.js:

var x = require('./x');
console.log(x.a);
module.require
  module.require方法提供一个加载模块的方法,就如从原始的module中调用require()。
  为了做这些,必须获取module对象的引用。require()返回exports,module仅在模块范围内可用,为了使用必须明确外置(export)。



总结
  当require()被调用时,为获取加载需要的精确 的文件名,使用require.resolve()函数。
  将上述所有综合,这是高等级(high-level)需要请求的伪代码(pseudocode)算法(algorithmin )。
  如下:



  停止require(X) from module at path Y


在路径Y上从模块中请求X
1、如果X是代码模块
a.返回代码模块。
b.停止
2、如果X以'./' 或者 '/' 或者 '../'开头。
a. 以文件加载(LOAD_AS_FILE(Y + X))
b. 以目录加载(LOAD_AS_DIRECTORY(Y + X))
3、加载节点模块(LOAD_NODE_MODULE(X, dirname(Y)))
4、抛出未找到异常"not found"。

作为文件加载 LOAD_AS_FILE(X)
1、如果X是一个文件,以JavaScript文本加载X。停止
2、如果X.js是一个文件,以JavaScript文本加载X。
3、如果X.node是一个文件,以二进制插件加载X.node。停止

作为目录加载  LOAD_AS_DIRECTORY(X)
1、如果X/package.json是一个文件,
a.解析X/package.json,并查找主要域('main' field)
b. 设置M = X + json主域(json main field)
c. 加载文件M
2、如果X/index.js是一个文件, 作为JavaScript文本加载X/inde.js。停止。
3、如果X/index.node是一个文件,作为一个二进制插件加载,停止。

加载节点模块  LOAD_NODE_MODULES(X, START)
1、设置DIRS = NODE_MODULES_PATHS(START)。
2、对于目录下的每个目录
a.加载文件(DIR/X) LOAD_AS_FILE(DIR/X)
b.加载目录(DIR/X) LOAD_DIRECTORY(DIR/X)
NODE_MODULES_PATHS(START)
1、设置PARTS = path split(START)
2、设置ROOT = PARTS中‘node_modules’的第一个实体的索引。
3、设置I = PARTS - 1
4、设置DIRS = []
5、while I > ROOT
a. 如果PARTS[I] = "node_modules" CONTINUE
c.DIR = (PARTS[0...I]+ 'node_modules'的联合路径)
b.DIRS = DIRS + DIR
c.设置I = I - 1 1. let PARTS = path split(START)
6、返回DIRS

从全局文件夹中加载 Loading from the global folders


  如果NODE_PATH环境变量设置成冒号分割(colon-delimited)的绝对路径的集合,如果在任何地方都没找到,node将会为模块查找这些目录。
  (注意:在Windows下,NODE_PATH分割是用分号代替冒号)

  此外,node还会搜索一下位置:
  1. $HOME/.node_modules
  2. $HOME/.node_libraries
  3. $PREFIX/lib/node
  


$HOME是用户home目录,$PREFIX是节点配置的安装前缀(installPrefix)。  这很具有历史意义。非常建议将依赖文件或包放置在node_modules文件夹中,这将会被快速加载,并且可靠。



访问主模块 Accessing the main module


  当一个文件直接在node中运行时,require.main被这只到module。意思就是说你可以决定一个文件在测试时是否已经被直接运行。
  require.main === module
  对于文件foo.js,如果执行node foo.js将为true。但通过require('./foo')时运行时为false。


因为module提供一个文件名属性(一般情况下等于_filename),当前应用的入口点可以通过检查require.main.filename获得。
  


附录:包管理技巧( Package Manager Tips)
  节点的语义require()函数被设计成一般足以支持一些健全的目录结构。包管理程序(Package manager )如:dpkg,rpm,和npm将有希望从node模块中不需要修改创建本地包。

  下面给出目录结构的建议:
  在/usr/node/<some-package>/<some-version>目录下面放置一个包的详细版本说明。
  包能够以来其它的。为了装载foo包,你必须装载包bar的版本说明。包bar有自己的依赖,在一些情况下,他们的依赖包可能形成碰撞,或互调循环。


因为node查找任何模块加载的真实路径,并在node_modules文件夹中根据上面的描述查找他们的依赖包,用下面的架构设计很容易解决尚需问题:



  • /usr/lib/node/foo/1.2.3/ - foo包的详细内容, 版本 1.2.3.

  • /usr/lib/node/bar/4.3.2/ - foo依赖的bar的详细说明

  • /usr/lib/node/foo/1.2.3/node_modules/bar - 象征连接到/usr/lib/node/bar/4.3.2/.

  • /usr/lib/node/bar/4.3.2/node_modules/* - bar依赖的象征连接到的包
  因此,即使遇到循环互调,或者依赖包冲突,每个模块将可以给出其所用到的依赖包版本。

  foo包中代码使用requirt("bar"),将给出版本连接到/usr/lib/node/foo/1.2.3/node_modules/bar。然后在bar包的代码中调用reuire(''quux),将给出版本连接到/usr/lib/node/bar/4.3.2/node_module/quux。
  此外,为使的模块最佳检查process,不是把包直接放置在/usr/lib/node下,可以将其放置在/usr/lib/node_moduls/<name>/<version>。node将不会再/usr/node_modules或/node_modules.查找缺失的依赖包。
  为使得模块对nod REPL可用,将/usr/lib/node_modules文件夹设置到$NODE_PATH的环境变量下可能很有用。因为模块检查使用的node_mudules文件夹都是相对路径,
  并且基于真实路径的文件调用require(),所以包可以在任何地方。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-345414-1-1.html 上篇帖子: nodeJS入门例子一—插件(Addons) 下篇帖子: nodeJS入门例子一概要(Synopsis)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表