JavaScript入门教程:http://www.w3school.com.cn/js/

深入学习推荐阅读Mozilla JavaScript:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide


    Node是一个可以让JavaScript运行在服务器端或者说运行在浏览器之外的平台。Node.js中所谓的JavaScript只是Core JavaScript,Node.js不运行在浏览器中,所以不存在JavaScript的浏览器兼容性问题,可以放心地使用JavaScript语言的所有特性。Node.js的JavaScript引擎是V8。Node.js是一个实时Web(Real-time Web)应用开发平台,充分考虑了在实时响应、超大规模数据要求下架构的可扩展性。它不同于传统平台依靠多线程来实现高并发的设计思路,而采用了单线程、异步I/O、事件驱动的程序设计模型。这些特性不仅带来了巨大的性能提升,还减少了多线程程序设计的复杂性,提高了开发效率。

    Node.js可以作为服务器向用户提供服务,与PHP、Python、Ruby on Rails相比,它跳过了Apache、Nginx等HTTP服务器,直接面向前端开发。

使用Nodejs可以轻松开发:

  • 具有复杂逻辑的网站;

  • 给予社交网络的大规模Web应用;

  • Web Socket服务器;

  • TCP/UDP套接字应用程序;

  • 命令行工具;

  • 交互式终端程序;

  • 带有图形用户界面的本地应用程序;

  • 单元测试工具;

  • 客户端JavaScript编译器;

    Node.js内建HTTP服务器支持,这个服务器不仅可以用来调试代码,而且本身就可以部署到产品环境,可以轻易地实现一个网站和服务器的组合。

nodejs编译安装

$./configure
$make
$sudo make install

$ node --help

Usage: node [options] [ -e script | script.js ] [arguments] 

       node debug script.js [arguments] 


Options:

  -v, --version        print node's version

  -e, --eval script    evaluate script

  -p, --print          evaluate script and print result

  -i, --interactive    always enter the REPL even if stdin

                       does not appear to be a terminal

  --no-deprecation     silence deprecation warnings

  --trace-deprecation  show stack traces on deprecations

  --v8-options         print v8 command line options

  --max-stack-size=val set max v8 stack size (bytes)


Environment variables:

NODE_PATH              ':'-separated list of directories

                       prefixed to the module search path.

NODE_MODULE_CONTEXTS   Set to 1 to load modules in their own

                       global contexts.

NODE_DISABLE_COLORS    Set to 1 to disable colors in the REPL


Documentation can be found at http://nodejs.org/

使用

$node script.js

$node -e "console.log('Hello world');"  //要执行的语句作为node -e 的参数直接执行

node的REPL(Read-eval-print-loop)模式:输入-求值-输出-循环

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

$node     //启动一个交互式shell

>

建立HTTP服务器 -- http 模块

建立一个名为example.js的文件,内容为:

  1 var http = require('http')
  2 http.createServer(function(req, res) {
  3     res.writeHead(200, {'Content-Type': 'Text/html'});
  4     res.write('<h1>Node.js</h1>');
  5     res.end('<p>Hello World!</p>');
  6     }).listen(8124, "127.0.0.1");
  7 console.log('Server running at http://127.0.0.1:8124');

运行$node example.js,打开浏览器访问http://127.0.0.1:8124/ 

Nodejs学习

    运行后不会立即退出,而是一直等待,直到按下Ctrl+C。listen函数创建了事件监听器,使得Node.js不会退出事件循环。


使用supervisor--监视代码代码的改动,并自动重启Node.js,解决了开发中调试的问题

$sudo npm install -g supervisor

Nodejs学习



异步式I/O与事件驱动--Node.js最大特点,其异步机制是基于事件的,通过回调函数实现。

    Nodejs使用单线程模型,对于所有I/O采用异步式的请求方式,避免频繁的上下文切换。Nodejs在执行过程中维护一个事件队列,程序在执行时进入事件循环等待下一个事件的到来,每个异步式I/O请求完成后会被推送到事件队列,等待程序进行处理。

                    网络通信、数据库查询-->事件循环<--客户端请求、磁盘I/O

    单线程事件驱动的异步式I/O(非阻塞模式):减少了多线程的开销,但是依然保证CPU高利用率和高吞吐量。

异步读取文件readfile.js:

  1 var fs = require('fs');                                                     
  2 
  3 function callback(err, data) {
  4     if(err) {
  5         console.log(err);
  6     } else {
  7         console.log(data);
  8     }
  9 }
 10 fs.readFile('file.txt', 'utf-8', callback);
 11 
 12 console.log('end.\n');

Nodejs学习

同步读取readfilesync.js:

 1 var fs = require('fs');
  2 var data = fs.readFileSync('file.txt', 'utf-8');
  3 console.log(data);
  4 console.log('end.\n');

Nodejs学习

    fs.readFile调用时只是将异步式I/O请求发给操作系统,然后立即返回执行后面的语句,执行完之后进入事件循环监听事件。当fs接收到I/O请求完成的事件时,事件循环主动调用回调函数完成后续工作。

    提示:Node.js的异步编程接口习惯是以函数的最后一个参数作为回调函数,通常一个函数只有一个回调函数。回调函数的实际参数中第一个是err,其余参数是其他返回的内容。如果没有错误发生,err值会是 null 或 undefined。如果有错误发生,err通常是Error对象的实例。

    与同步I/O函数不同,Node.js中异步函数大多没有返回值。

Node.js中,并不是所有的API都提供同步和异步版本。Node.js不鼓励使用同步I/O.


事件 -- events 模块

    Node.js程序由事件循环开始,到事件循环结束,所有的逻辑都是事件的回调函数。Nodejs的事件循环对开发者不可见,由libev库实现,并被EventEmitter封装。

    事件由EventEmitter对象提供,event对象注册事件some_event监听器,通过setTimeout在1000ms之后向event对象发送事件some_event,此时调用some_event监听器。

event.js

  1 var EventEmitter = require('events').EventEmitter;                          
  2 var event = new EventEmitter();
  3 event.on('some_event', function() {
  4     console.log('Some event occured.');
  5 });
  6 setTimeout(function() {
  7     event.emit('some_event');
  8 }, 1000);

结果:


$ node event.js 

Some event occured.

模块和包

    Node.js提供require函数调用其它模块,而且模块都是基于文件的,文件和模块是一一对应的。一个Node.js文件就是一个模块,这个文件可能是JavaScript代码、JSON或者编译过的C/C++扩展。

例如http是nodejs的一个核心模块,其内部用C++实现,外部用JavaScript封装。通过require函数获取这个模块,然后使用其对象。

1.创建模块:

    创建一个文件,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


2.单次加载

    require不会重复加载模块

loadmodule.js

//loadmodule.js
var hello1 = require('./module');
hello1.setName('No 1');

var hello2 = require('./module');
hello2.setName('No 2');

hello1.sayHello();
hello2.sayHello();

运行结果:

$ node loadmodule.js 

Hello No 2

Hello No 2

变量hello1和hello2指向同一个实例,结果被覆盖。


3.覆盖exports

    如果将一个对象Hello封装到模块中,如果使用 exports.Hello = Hello,则在其他文件中需要通过

require('./modulefile').Hello获取Hello对象。

简化方法是使用 module.exports = Hello 代替

hello.js

//hello.js

function Hello() {
	var name;

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

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

module.exports = Hello;

getmodule.js

//getmodule.js
var HelloObj = require('./hello');

myModule = new HelloObj();
myModule.setName('BYE HELLO');
myModule.sayHello();

运行结果:

$ node getmodule.js 

Hello BYE HELLO

   exports本身仅仅是一个普通的空对象,即{},它专门用来声明接口,本质上是通过它为模块闭包的内部建立了一个有限的访问接口。因为没有特殊的地方所以可以用其他东西来代替,如 exports.Hello = Hello 中的Hello对象;但是使用时需要通过require('./modulefile').Hello获取Hello对象。使用module.exports = Hello ,在外部引用该模块时,其接口对象就是要输出的 Hello 对象本身,而不是原先的exports。不可以通过对exports直接赋值代替对module.exports赋值。exports实际只是一个和module.exports指向同一个对象的变量,它本身会在模块执行结束后释放,但module不会,因此只能通过指定module.exports来改变访问接口。

创建包

Node.js包是一个目录,其中包含一个JSON格式的包说明文件package.json。严格符合CommonJS规范的包应该具备以下特征

  • package.json必须在包的顶层目录下;

  • 二进制文件应该在bin目录下;

  • JavaScript代码应该在lib目录下;

  • 文档应该在doc目录下;

  • 单元测试应该在test目录下。

  1. 作为文件夹的模块--最简单的包

    ./somepackage/index.js  

//somepackage/index.js

exports.hello = function() {
	console.log('Hello.');
};

    getpackage.js

//getpackage.js
var somePackage = require('./somepackage');
somePackage.hello();

运行结果:

$ node getpackage.js 

Hello.

2.package.json

添加文件package.json

$ cat ./somepackage/package.json 

{

"main" : "./lib/interface.js"

}

新建lib文件夹,将index.js文件重命名为interface.js放入lib文件夹下

$ cat ./somepackage/lib/interface.js 

//somepackage/lib/index.js
exports.hello = function() {
console.log('Hello.');
};

再次运行:

$ node getpackage.js 

Hello.

    Node.js在调用某个包时,会首先检查包中package.json文件的main字段,将其作为包的借口模块,如果package.json文件或main字段不存在,则尝试寻找index.js或index.node作为包的接口。


Node.js包管理器--npm

    $npm [install/i] [-g] [package_name]

    注意区别本地安装和全局安装,本地模式安装的包可通过require使用,但是不会注册PATH,无法通过命令全局使用;全局模式相反,注册PATH可以直接通过命令使用,但是无法通过require使用。因此,如果要把某个包作为工程运行时的一部分,通过本地模式获取,如果要在命令下使用,则使用全局模式安装。

创建全局链接 npm link

    使用 npm link 命令可以使全局安装的包通过require使用。

例如 npm install -g express 全局安装了express,这时在工程目录下运行命令:

$ npm link express

/home/nick/nodejs/somepackage/node_modules/express -> /usr/local/lib/node_modules/express

    则在node_modules子目录中发现一个指向安装到全局包的符号链接

 express -> /usr/local/lib/node_modules/express/   这样全局包就可以当作本地包使用了。

    在包目录(package.json所在目录)运行 npm link 命令,可以将本地包链接到全局,利用这种方法可以非常方便地在不同的工程间测试要开发的包。

包的发布--npm init

    根据交互式问答产生一个符合标准的package.json,创建一个index.js作为包的接口,一个简单的包就制作完成了。

npm adduser -- 创建帐号,用于今后维护自己的包,完成之后使用 npm whoami 检测是否已经取得帐号。然后在package.json所在目录下运行  npm publish 完成发布,可以在 https://www.npmjs.org/ search 自己刚刚发布的包,通过npm install package_name就可以安装自己发布的包了。

    如果包有更新,只需修改package.json文件的version字段,重新 npm publish;如果对包不满意,可以使用 npm unpublish 命令取消发布。


调试

1.命令行调试

Usage: node debug script.js

Commands: run (r), cont (c), next (n), step (s), out (o), backtrace (bt), setBreakpoint (sb), clearBreakpoint (cb), watch, unwatch, watchers, repl, restart, kill, list, scripts, breakOnException, breakpoints, version

Nodejs学习


debug.js

//debug.js
var a = 1;
var b = 'world';

var c = function(x) {
	console.log('hello ' + x + a);
};

c(b);

$ node debug debug.js 

< debugger listening on port 5858

connecting... ok

break in debug.js:2

  1 //debug.js

  2 var a = 1;

  3 var b = 'world';

  4 

debug> n

break in debug.js:3

  1 //debug.js

  2 var a = 1;

  3 var b = 'world';

  4 

  5 var c = function(x) {

debug> sb('debug.js', 4)

  1 //debug.js

  2 var a = 1;

  3 var b = 'world';

* 4 

  5 var c = function(x) {

  6 console.log('hello ' + x + a);

  7 };

  8 

debug> c

break in debug.js:5

  3 var b = 'world';

* 4 

  5 var c = function(x) {

  6 console.log('hello ' + x + a);

  7 };

debug> repl

Press Ctrl + C to leave debug repl

> a

1

> b

'world'

2.远程调试--基于V8

     node --debug[=port] script.js

     node --debug-brk[=port] script.js

    node --debug 命令选项启动调试服务器,默认端口55858,指定使用 --debug=1234。使用 -- debug 选项运行脚本,脚步正常执行,不会暂停,执行过程中调试客户端可以连接到调试服务器。如果要求脚步暂停执行等待客户端连接,则使用 --debug-brk 选项,调试服务器在启动之后立刻暂停执行脚步,等待调试客户端连接。

    一个终端:

$ node --debug-brk debug.js 

debugger listening on port 5858

    另一个终端:

$ node debug 127.0.0.1:5858

connecting... ok

debug> n

break in nodejs/debug.js:3

  1 //debug.js

  2 var a = 1;

  3 var b = 'world';

  4 

  5 var c = function(x) {

debug> 

3.使用node-inspector

$ sudo npm install -g node-inspector   //安装

$ node --debug-brk debug.js      //连接要调试的脚本

$ node-inspector       //启动node-inspector

Node Inspector v0.7.4

Visit http://127.0.0.1:8080/debug?port=5858 to start debugging.

Nodejs学习注:node-inspector(使用了WebKit Web Inspector)只能在Chrome、Safari等WebKit内核的浏览器中使用。

4.在Eclipse中安装V8调试工具调试Node.js代码

启动Eclipse之后,Help-》Install New Software...,Add Repository,添加 Chrome Developer Tools, 用于调试Javascript代码。Debug -> Debug Configurations...,找到Standalone V8 VM, New产生一个新配置,填好Name,Host,Port;然后使用命令 node --debug-brk=port script.js命令启动要调试脚本的调试服务器。

Nodejs调试技术总结