Node.js教程

NodeJs入门之事件驱动

  首先下载安装,非常简单,从http://nodejs.org下载。如果想自己编译,参考这里

如果是windows,直接运行node.js,会打开一个窗口,键入:

console.log("Hello World");

会看到结果。

用编辑器编辑一个hello.js文本文件,输入:

console.log("Hello World");
存盘退出,cmd到windows的命令行,运行node
node hello.js

会看出输出。

Web服务器

   编辑一个文本文件server.js,输入:

var http = require("http");

http.createServer(function(request, response) {
  response.writeHead(200, {"Content-Type": "text/plain"});
  response.write("Hello World");
  response.end();
}).listen(8888);

运行 node server.js

用浏览器打开 http://localhost:8888/,会看到

Hello World
 

   分析代码如下: 第一行需要Node.js附带的的HTTP模块,使得它通过变量的http访问。我们调用的HTTP模块提供的功能之一:createServer。这个函数返回一个对象,这个对象有一个方法名为listen,并以一个数值表示我们的HTTP服务器将侦听的端口号。response是负责输出浏览器的响应部分。

事件驱动

   NodeJS以事件驱动著名,通过异步的编程达到高吞吐量高性能。

var http = require("http");

function onRequest(request, response) {
  console.log("Request received.");
  response.writeHead(200, {"Content-Type": "text/plain"});
  response.write("Hello World");
  response.end();
}

http.createServer(onRequest).listen(8888);

console.log("Server has started.");

  这个代码我们使用函数onRequest封装了请求的处理部分。当我们启动它会立即输出“Server started”。在我们的浏览器中打开http://localhost:8888/,会显示消息“Request received."

   这两个代码的主要区别是,前者将处理部分写在http.createServer中,按照传统思路,启动服务器后,遇到这段代码会去运行,如果运行时间很长,导致暂停,非常没有效率。如果第二位用户请求的服务器,而它仍然在服务第一个请求,那第二个请求只能回答第一个完成后才能应答,这就是堵塞式的Socket IO的问题。  

   Node.js的通过一个低级别的C / C + +层将异步执行有关IO的操作,一旦监听到请求, Node.js将执行您作为参数传递到I / O操作函数的回调函数,如上面的onRequest。这个异步操作关键是基于事件轮询机制。

事件轮询机制

    Node.js的事件循环是靠一个单线程不断地查询队列中是否有事件,见单写原则,当它读取到一个事件时,将调用与这个事件关联的javascript函数,如果这个函数是执行一个IO操作,比如侦听一下8888端口是否有Scoket链接,Node.js会启动这个IO操作,但是不会等待IO操作结束,而是继续到队列中查看是否有下一个事件,如果有,就处理这个事件。

   下面关键来了,花开两朵,各表一枝,那么最好还是要会合的,nodejs如何知道启动的IO操作是否执行,执行的结果如何呢?比如发现我们浏览器访问8888端口,这时IO操作侦听到一个请求,那么下一步应该执行上面的onRequest了,但是Nodejs管理的CPU正在做其他事情啊。

  这里,IO操作结束后会自己将一个执行原始回调函数的引用加入到事件队列中,也就是onRequest这个函数加入到事件队列中,NodeJS因为一直在轮询这个事件队列,会发现这个事件,执行事件的函数onRequest,完成用户的处理。

  从这里已经注意到,我们前后两个代码,一个是将函数体代码写入http:

http.createServer(function(request, response) {

//函数体开始
  response.writeHead(200, {"Content-Type": "text/plain"});
  response.write("Hello World");
  response.end();

//函数体结束
}).listen(8888);

  另外一个是用onRequest替代这部分代码,这个onRequest很重要,可以作为一个事件放入事件队列中,而函数体这段代码是无法放入事件队列中的,而且无法被另外一个函数调用。

  普通的JS函数如下:

function myfunc(param){

   alert("hello" + param);

}

但是我们为了传入其他函数作为函数参数,会如下写:

var myfunc = function (param){

   alert("hello" + param);

}

如果有另外一个函数调用这个函数:

function myfunc2(myfunc){

myfunc();

}

  那么我们就可以通过myfunc2(myfunc)完成对原来 函数的回调。如果将myfunc这个函数放入事件队列中,语法类似queue.add(myfunc),通过类似queue.poll()语句读取到这个事件的线程就会如此完成对myfunc的回调。

  JavaScript支持闭包和它将函数作为第一等公民,意味着它非常适合导入Node.js并提供事件触发的编程模型。

下页

Node.js的事件轮询Event Loop原理解释

Node.js 视频入门

PayPal从Java迁移到Node.js

Scala入门之函数编程

vertx入门教程

Play框架入门使用

异步编程

EDA专题