node学习笔记

1、Node,可以让javascript运行在服务器端的平台。

   是一个为实时Web(Real-time Web)应用开发而诞生的平台。充分考虑了实时响应,超大规模数据要求下架构。

2、摒弃了传统平台依靠多线程来实现高并发的设计思路,而采用了单线程、异步式I/O,事件驱动式的程序设计模型。

不仅带来了巨大的性能提升,还减少了多线程程序设计复杂性,进而提高了开发效率。

3、单线程事件驱动的异步I/O。

单线程事件驱动的异步I/O比传统的多线程阻塞式I/O到底好在哪里:简而言这,异步式I/O少了多线程的开销。对操作

系统来说,创建一个线程的代价是十分昂贵的,需要给它分配内存、列入调度,同时在线程切换的时候还要执行内存换页,

CPU的缓存被清空,切换回来的时候还要重新从内存中读取信息,破坏了数据的局部性。

4、Node.js 的事件循环机制

Node.js 在什么时候会进入事件循环呢?答案是 Node.js 程序由事件循环开始,到事件循

环结束,所有的逻辑都是事件的回调函数,所以 Node.js 始终在事件循环中,程序入口就是

事件循环第一个事件的回调函数。

5、模块(Module)和包(Package)是 Node.js 最重要的支柱。

6、事件:Node.js所有的异步I/O操作在完成时都会发送一个事件到事件队列。在开发者看来,事件由EventEmitter对象提供。

前面提到的fs.readFile和http.createServer的回调函数都是通过EventEmitter来实现的。

7、我们可以把要执行的语句作为node -e的参数直接执行。例如:node -g "cosole.log('Hello World');"

8、使用node的REPL模式。REPL(Read-eval-print loop),即输入-求值-输出循环。运行无参数node将会启动一

个JavaScrit的交互式shell:

例如:                      

进入repl模式后,会出现一个">"提示符提示你输入命令,输入后按回车,Node.js将会解析并执行命令。如果你执行了一个函数,那么REPL还会在下面显示这个函数的返回值。上面的undefined就是console.log的返回值。如果你输入了一个错误的指令,REPL 则会立即显示错误并输出调用栈。在任何时候,连续按两次 Ctrl + C 即可推出Node.js 的 REPL 模式。

node 提出的 REPL 在应用开发时会给人带来很大的便利,例如我们可以测试一个包能否正常使用,单独调用应用的某一个模块,执行简单的计算等。

9、事实上脚本文件的扩展名不一定是js,例如我们将脚本保存为script.txt,使用node script.txt命令同样可以运行。扩展名使用.js只是一个约定而已,遵循了JavaScript脚本一贯的命名习惯。

10、 在开发 Node.js 实现的 HTTP 应用时会发现,无论你修改了代码的哪一部份,都必须终止Node.js 再重新运行才会奏效。这是因为 Node.js 只有在第一次引用到某部份时才会去解析脚本文件,以后都会直接访问内存,避免重复载入。Node.js的这种设计虽然有利于提高性能,却不利于开发调试,因为我们在开发过程中总是希望修改后立即看到效果,而不是每次都要终止进程并重启。supervisor 可以帮助你实现这个功能,它会监视你对代码的改动,并自动重启 Node.js。

使用方法很简单,首先使用 npm 安装 supervisor:

$ npm install -g supervisor

如果你使用的是 Linux 或 Mac,直接键入上面的命令很可能会有权限错误。原因是 npm

需要把 supervisor 安装到系统目录,需要管理员授权,可以使用 sudo npm install -g

supervisor 命令来安装。

使用 supervisor 命令启动 app.js:

$ supervisor app.js

当代码被改动时,运行的脚本会被终止,然后重新启动。supervisor 这个小工具可以解决开发中的调试问题。

11、回调函数

让我们看看在 Node.js 中如何用异步的方式读取一个文件,下面是一个例子:

//readfile.js

var fs = require('fs');

fs.readFile('file.txt', 'utf-8', function(err, data) {

if (err) {

console.error(err);

} else {

console.log(data);

}

});

console.log('end.');

运行的结果如下:

end.

Contents of the file.

要想理解结果,我们必须先知道在 Node.js 中,异步式 I/O 是通过回调函数来实现的。fs.readFile 接收了三个参数,第一个是文件名,第二个是编码方式,第三个是一个函数,我们称这个函数为回调函数。JavaScript 支持匿名的函数定义方式, 譬如我们例子中回调函数的定义就是嵌套在fs.readFile 的参数表中的。这种定义方式在 JavaScript 程序中极为普遍,与下面这种定义方式实现的功能是一致的:

//readfilecallback.js

function readFileCallBack(err, data) {

if (err) {

console.error(err);

} else {

console.log(data);

}

}

var fs = require('fs');

fs.readFile('file.txt', 'utf-8', readFileCallBack);

console.log('end.');

fs.readFile 调用时所做的工作只是将异步式 I/O 请求发送给了操作系统,然后立即

返回并执行后面的语句,执行完以后进入事件循环监听事件。当 fs 接收到 I/O 请求完成的

事件时,事件循环会主动调用回调函数以完成后续工作。因此我们会先看到 end.,再看到

file.txt 文件的内容。

12、模块和包

模块(Module)和包(Package)是Node.js最重要的支柱。

Node.js提供了require函数来调用其他模块,而且模块都是基于文件的,机制十分简单。

我们经常把Node.js的模块和包相提并论,因为模块和包是没有本质区别的,两个概念也时常混淆。如果要辨析,那么可以把包理解成是实现了某个功能模块的集合,用于发布和维护。

13、模块是Node.js应用程序的基本组成部分,文件和模块是一一对应的。换言之,一个Node.js文件就是一个模块,这个文件可能是JavaScript代码、JSON或者编译过的C/C++扩展。

例如:var http=require(‘http’),其中http就是Node.js的一个核心模块,其内部是用C++实现的,外部用javaScript封装。我们通过require函数获取这个模块,然后才能使用其中的对象。

14、Node.js提供了exports和require两个对象,其中exports是模块公开的接口,require用于从外部获取一个模块的接口,即所获取模块的exports对象。

让我们以一个例子来了解模块。创建一个 module.js 的文件,内容是:

//module.js

var name;

exports.setName = function(thyName) {

name = thyName;

};

exports.sayHello = function() {

console.log('Hello ' + name);

};

在同一目录下创建 getmodule.js,内容是:

//getmodule.js

var myModule = require('./module');

myModule.setName('BYVoid');

myModule.sayHello();

运行node getmodule.js,结果是:

Hello BYVoid

在以上示例中,module.js 通过 exports 对象把 setName 和 sayHello 作为模块的访

问接口,在 getmodule.js 中通过 require('./module') 加载这个模块,然后就可以直接访

问 module.js 中 exports 对象的成员函数了。

这种接口封装方式比许多语言要简洁得多,同时也不失优雅,未引入违反语义的特性,

符合传统的编程逻辑。在这个基础上,我们可以构建大型的应用程序,npm 提供的上万个模

块都是通过这种简单的方式搭建起来的。

15、单次加载

上面这个例子有点类似于创建一个对象,但实际上又和对象有本质区别,因为require不会重复加载模块,也就是说无论调用多少次require,获取的模块都是同一个。

看下列代码:

//loadmodule.js

var hello1 = require('./module');

hello1.setName('BYVoid');

var hello2 = require('./module');

hello2.setName('BYVoid 2');

hello1.sayHello();

运行后发现结果是Hello BYVoid 2,这是因为变量hello1,hello2指向的是同一对象,因为hello1.setName的结果被hello2.setName覆盖,最终输入结果是由后者决定的。

 

posted @ 2017-08-16 09:51  liuxixi  阅读(284)  评论(0编辑  收藏  举报