Nodejs学习笔记

Nodejs特性

异步I/0

Nodejs是异步I/O的实现方式,如同Ajax一样,用户不需要等待请求的完成再进行下一步操作,而是通过回调函数实现,Nodejs读取文件实例:

1
2
3
4
5
6
var fs =  require('fs');

fs.readFile('/path',function(){err,file}{
console.log('读取文件完成');
});
console.log('发起读取文件');

“发起读取文件”会在“读取文件完成”之前输出。

单线程

Node是单线程的,我们不需要处处在意状态的同步问题,这里没有死锁的存在,也没有线程上下文交换所带来的性能上的开销。但也会有一些不好的地方:
-无法利用多核CPU
-错误会引起整个应用退出,应用的健壮性值得考验
-大量计算占用CPU导致无法继续调用异步I/O
Node采用了与Web Workers相同的思路,使用子进程来解决单线程大计算量的问题,通过将计算分发到各个子进程来将大量计算分解掉。

模块机制

CommonJS规范

1、Javascript在浏览器前端的规范覆盖的范畴很小,主要包含词法、类型、上下文、表达式、声明、方法、对象等语言的基本要素。
2、CommonJS主要为了弥补js没有模块系统、标准库较少、没有标准接口、缺乏包管理系统的缺陷。
3、CommonJS API写出的应用可以具备跨宿主环境执行的能力,这样不仅可以利用javascript开发富客户端应用,而且还可以编写以下应用。
-服务器端JavaScript应用程序
-命令行工具
-桌面图形界面应用程序
-混合应用(Titanum和Adobe AIR等形式的应用)

CommonJS的模块规范

1、模块引用示范:

1
var math = require('math');

2、模块定义
上下文提供了exports对象用于导出当前模块的方法或者变量,并且它是唯一导出的出口。

1
2
3
4
5
6
7
8
9
10
11
//math.js
exports.add = function(){
var sum = 0,
i = 0,
args = arguments,
l = args.lenght,
while(i<l){
sum += args[i++];
}
return sum;
}

Node的模块实现

1、Node引入模块的3个步骤:路径分析、文件定位、编译执行。
2、Node模块的分类:核心模块(自带,加载速度快)和文件模块(用户编写)。
3、优先从缓存读取,然后才是查找。
4、模块标识符主要有:

  • 核心模块,如http、fs、path等
    • 自定义的不能与核心模块相同标识符,除非使用不同的标识符名或者换用路径
  • .或..开始的相对路径文件模块
  • 以/开始的绝对路径文件模块
  • 非路径形式的文件模块,如自定义的connect模块,查找规则如下:
    • 当前文件目录下的node_modules目录
    • 父目录下的node_modules目录
    • 父目录的父目录下的node_modules目录
    • 沿路径向上逐级递归,直到根目录下的node_modules目录

5、文件扩展名分析,CommonJS允许标识符不包含文件扩展名,这种情况下,Node会按.js、.node、.json的次序补足扩展名依次尝试。在尝试的过程中需要调用fs模块同步阻塞式地判断文件是否存在,因为Node是单线程,所以会引起一些性能问题,如果是.node和.json文件,传递给require的时候带上扩展名,另外,同步配合缓存。
6、目录分析和包(这点要网上查查)
7、对于不同的文件扩展名,采用不同的载入方法:

  • .js文件。通过fs模块同步读取文件后编译执行。
  • .node文件。这是用C/C++编写的扩展文件,通过dlopen()方法加载最后编译生成的文件。
  • .json文件。通过fs模块同步读取文件后,用JSON.parse()解析返回结果。
  • .其他扩展名文件。他们都被当成.js文件载入。
    8、每一个编译成功的模块都会将其文件路径作为索引缓存在Module._cache对象上,以提高二次引入的性能。(主要针对文件模块)
    9、每个模块都存在着require、exports、module和_filename、_dirname变量,原因是编译过程中,Node对获取的javascript文件内容进行了头尾包装,一个正常的JavaScript文件会被包装成如下的样子:
    1
    2
    3
    4
    5
    6
    (function(exports,require,module,_filename,_dirname){
    var math = require('math');
    exports.area = function(radius){
    return Math.PI * radius * radius;
    };
    });

10、核心模块分为C/C++(存放在src目录)编写和JavaScript(存放在lib目录)编写两部分.
11、文件模块依赖核心模块(JavaScript),核心模块依赖内建模块(C/C++)。