一、Node,可让javascript运行在服务器端的平台。javascript
是一个为实时Web(Real-time Web)应用开发而诞生的平台。充分考虑了实时响应,超大规模数据要求下架构。java
二、摒弃了传统平台依靠多线程来实现高并发的设计思路,而采用了单线程、异步式I/O,事件驱动式的程序设计模型。node
不只带来了巨大的性能提高,还减小了多线程程序设计复杂性,进而提升了开发效率。shell
三、单线程事件驱动的异步I/O。npm
单线程事件驱动的异步I/O比传统的多线程阻塞式I/O到底好在哪里:简而言这,异步式I/O少了多线程的开销。对操做编程
系统来讲,建立一个线程的代价是十分昂贵的,须要给它分配内存、列入调度,同时在线程切换的时候还要执行内存换页,缓存
CPU的缓存被清空,切换回来的时候还要从新从内存中读取信息,破坏了数据的局部性。服务器
四、Node.js 的事件循环机制多线程
Node.js 在何时会进入事件循环呢?答案是 Node.js 程序由事件循环开始,到事件循架构
环结束,全部的逻辑都是事件的回调函数,因此 Node.js 始终在事件循环中,程序入口就是
事件循环第一个事件的回调函数。
五、模块(Module)和包(Package)是 Node.js 最重要的支柱。
六、事件:Node.js全部的异步I/O操做在完成时都会发送一个事件到事件队列。在开发者看来,事件由EventEmitter对象提供。
前面提到的fs.readFile和http.createServer的回调函数都是经过EventEmitter来实现的。
七、咱们能够把要执行的语句做为node -e的参数直接执行。例如:node -g "cosole.log('Hello World');"
八、使用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 在应用开发时会给人带来很大的便利,例如咱们能够测试一个包可否正常使用,单独调用应用的某一个模块,执行简单的计算等。
九、事实上脚本文件的扩展名不必定是js,例如咱们将脚本保存为script.txt,使用node script.txt命令一样能够运行。扩展名使用.js只是一个约定而已,遵循了JavaScript脚本一向的命名习惯。
十、 在开发 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 这个小工具能够解决开发中的调试问题。
十一、回调函数
让咱们看看在 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 文件的内容。
十二、模块和包
模块(Module)和包(Package)是Node.js最重要的支柱。
Node.js提供了require函数来调用其余模块,并且模块都是基于文件的,机制十分简单。
咱们常常把Node.js的模块和包相提并论,由于模块和包是没有本质区别的,两个概念也时常混淆。若是要辨析,那么能够把包理解成是实现了某个功能模块的集合,用于发布和维护。
1三、模块是Node.js应用程序的基本组成部分,文件和模块是一一对应的。换言之,一个Node.js文件就是一个模块,这个文件多是JavaScript代码、JSON或者编译过的C/C++扩展。
例如:var http=require(‘http’),其中http就是Node.js的一个核心模块,其内部是用C++实现的,外部用javaScript封装。咱们经过require函数获取这个模块,而后才能使用其中的对象。
1四、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 提供的上万个模
块都是经过这种简单的方式搭建起来的。
1五、单次加载
上面这个例子有点相似于建立一个对象,但实际上又和对象有本质区别,由于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覆盖,最终输入结果是由后者决定的。