1.Node.js是什么
Node.js是一个让JS运行在服务器端的开发平台,它可以作为服务器向用户提供服务。Node.js中的
javascript只是Core javascript,或者说是ECMAJavaScript的一个实现。
2.Node.js能做什么
JS是为客户端为生,而Node.js是为网络而生。利用它可以轻松的开发出很多网站、社交应用、服务
器等等。
Node.js内建有一个HTTP服务器支持,可以实现一个网站和服务器的组合。
3.异步式I/O和事件驱动
Node.js最大的特点就是采用异步式I/O和事件驱动的架构设计。对于所有I/O都采用异步式的请求方
式,避免了上下文切换所带来的耗费系统资源、死锁、同步、低速连接攻击等问题。Nodejs在执行的过程中会维护一个事件队列,程序在执行时进入事件循环等待下一个事件的带来。每个异步式IO请求完成以后会被推送到事件队列,等待程序进程进行处理。 Node.js进程在同一时刻只会处理一个事件,完成以后立
即进入事件循环检查并处理后面的事件。这样,CPU和内存同一时刻只会处理一个事件并且尽可能让耗时的I/O操作并行执行。
缺点就是不符合传统开发者的变成思维,往往需要把一个完整的逻辑拆分成为一个个事件,增加了开
发和调试难度。
4.console.log()相当于C的printf(),也可以接受任意个参数,支持%d,%s的变量引用

eg: console.log('%s:%d','hello',25);
 // hello:25
 // undefined(这个是返回值 )


5.在终端输入node 回车 便可以进入REPL模式 可以直接写入JS代码运行
6.与传统服务器语言不同的是(以PHP为例)
浏览器--HTTP服务器--PHP解释器
而Node.js直接将服务器抽离,直接面向浏览器用户
浏览器--Node
7.创建一个http服务器

//app.js 
 var http = require('http'); //调用HTTP模块
 http.createServer(function(req, res) { //创建服务器
 res.writeHead(200, {'Content-Type': 'text/html'});
 res.write('<h1>Node.js</h1>');
 res.end('<p>Hello World</p>');
 }).listen(3000); //监听3000端口号 console.log("HTTP server is listening at port 3000.");


在终端运行 node app.js(注意要找到当前目录下)
会发现现在NOED一直在等待,进程不会退出事件循环。就无法实现实时刷新页面,不利于调试,因此可以安装一个模块supervisor
eg:$npm install -g supervisor
退出CTRL+C当前栈,运行 supervisor app.js
当代码改动的时候,运行的脚本被停止,然后重新启动,刷新页面,就可以看到实时刷新的数据。
8.阻塞与线程
1.同步式I/O(阻塞式I/O)
线程在执行中如果遇到磁盘读写或网络通信,通常要耗费较长时间。这时OS会剥夺这个线程的CPU控制权,使其暂停执行。同时将资源让给其他的工作线程,这种线程调度方式称之为阻塞,当I/O操作完毕时,OS将这个线程的阻塞状态解除,回复CPU对其的控制权,令其继续执行。
1.异步式读取文件

var fs = require('fs'); //请求FS模块
 fs.readFile('file.txt','utf-8',function(err,data){ //读取文件


(当前目录/指定目录下的文件名 文件格式 回调函数(错误,文件里的数据))

if(err){
 console.log(err);
 }else{
 console.log(data);
 }
 });
 console.log('end');


可以看到先打印end然后在打印err或者data;
2.同步式读取文件

var fs = require('fs');
 fs.readFileSync('file.txt','utf-8',function(err,data){//选择同步模式读取文件
 if(err){
 console.log(err);
 }else{
 console.log(data);
 }
 });


可以看到先打印err或者data再打印end

2.异步式I/O(非阻塞式I/O)
针对所有I/O操作不采用阻塞策略,当线程遇到I/O操作时,只是把请求发送给OS,继续执行下一条语句,当OS完成I/O操作时,以事件的形式通知执行I/O操作的线程,线程在特定的时候处理这个事件。因此,node有事件循环机制,不断的检查有没有未处理的事件,依次进行处理。
3.二者区别:
非阻塞模式下,一个线程永远在执行计算操作,CPU利用率为100%,I/O以事件的形式通知。
阻塞模式下,多线程往往能提高系统吞吐量,因为一个线程阻塞还有其他线程。
具体:
同步式I/O 异步式I/O
利用多线程提高吞吐量 单线程可实现提高吞吐量
通过事件片分割和线程调度利用多核CPU 通过功能划分利用多核
需要操作系统调度多线程使用多核CPU 可以将单线程绑定到单核CPU
难以充分利用CPU资源 充分利用CPU资源
内存轨迹大,数据局部性弱 内存轨迹小,数据局部性强
符合线性的编程思维 不符合传统变成思维
4.在node环境下可以直接运行JS代码
比如:node //进入node环境

Console.log(‘NEVER GIVE UP’);//在终端上打印出NEVER GIVE UP
 //第二行undefined是返回值


PS:不能用alert,因为alert是window下的一个方法
或者运行JS文件
比如hello.js文件
直接 node hello.js便可以执行

9.Node所有的异步I/O操作在完成时都会发送一个事件到事件队列。然后通过轮询机制触发事件。

//event.js
 var EventEmitter = require('events').EventEmitter;//请求事件对象
 var event = new EventEmitter(); //实例化对象 event.on('some_event', function() { //注册事件some_event的一个监听器
 console.log('some_event occured.');
 }); setTimeout(function() { //1000MS后向event对象发送事件
 event.emit('some_event');
 }, 1000);


2.事件的循环机制
1.node.js程序是由事件循环开始,到事件循环结束。所有的逻辑都是基于事件的回调函数
2.事件的回调函数在执行的过程中,可以能会发出I/O请求或者直接触发(emit)事件,执行完毕以后再返回事件循环。事件循环会检查事件队列中有没有未处理的事件,直
到检测不到时才退出事件循环,进程结束。
10.模块和包是NODE最重要的支柱。开发一个具有一定规模的程序不可能只用一个文件,通常需要把各个功能拆分、安装,然后组合起来,模块证实为了实现这种方式而诞生。包和模块本质上没有区别,只不过包是由多个模块组成,是在模块基础上提供更高层的抽象。
//module.js
1.加载模块

var name;
 exports.setName = function(thyName) { //将setName暴露给外界
 name = thyName;
 };
 exports.sayHello = function() { //将sayHello暴露给外界
 console.log('Hello ' + name);
 }; 
 //getmodule.js var myModule = require('./module');//请求加载module.js这个模块
 myModule.setName('Andy'); //调用module.js里面的方法
 myModule.sayHello();


最终输出Hello Andy
2.单次加载

var myModule1 = require('./module');
 myModule.setName('Andy'); var myModule2 = require('./module');
 myModule.setName('King'); myModule.sayHello();//Hello King


因为他们指向了同一个实例,myModule1被myModule2覆盖
3.覆盖exports

function Hello() {
 var name;

 this.setName = function (thyName) {
 name = thyName;
 };

 this.sayHello = function () {
 console.log('Hello ' + name);
 };
 };

exports.Hello = Hello; //前Hello是一个暴露属性给外界 后面的hello是指 function Hello
这样想获取hello对象就需要require('./filename').Hello来获取hello对象
!麻烦。
如果最后一行这样引用module.exports = Hello;这样只要var Hello = require('./hello');就
可以了.
注意:在外部引用该模块时,其接口对象就是要输出Hello对象本身,而不是原先的expots.
exports本身一个普通的空对象{},专门用于声明接口,可以用其他东西来代替,譬如Hello对象。但是i不可以通过对exports直接复制代替module.exports赋值,虽然他们指向同一个变量,但是
exports本身会在模块执行结束以后释放,module不会,因此只能通过module.exports来改变接口。

11.node debug XXX.js可以进入debug调试

node --debug[=port] script.js
 node --debug-brk[=port] script.js可以进入远程调试 默认端口为5858