`
rainsilence
  • 浏览: 158876 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

NodeJs中的非阻塞方法

阅读更多

首先我们利用NodeJs先构建一个基本的服务器。

 

index.js

 

var requestHandler = require("./requestHandler");
var server = require("./server");

var route = {
	"/hello": requestHandler.hello,
	"/upload": requestHandler.upload
};

server.start(route);

 

server.js

 

var http = require("http");
var url = require("url");

exports.start = function(route) {
	var server = http.createServer(function(req, res) {
		
		var pathName = url.parse(req.url).pathname;
		
		var handler = route[pathName];
		
		if (handler) {
			
			console.log("Through path:" + pathName + ":" + new Date().getTime());
			
			handler(res);
			
		} else {
			res.writeHead(404, {"Content-Type": "text/plain"});
			res.end();
		}
	});

	server.listen(8088);
};

 

requestHandler.js

 

exports.hello = function(res) {

	res.writeHead(200, {"Content-Type": "text/plain"});
		
	res.write("say hello.");
		
	res.end();
};

exports.upload = function(res) {
	res.writeHead(200, {"Content-Type": "text/plain"});
	
	res.write("upload");
	
	res.end();
};

 

在cmd中,键入node index.js即可启动。

 

但是,上面的代码是阻塞的。如果在createServer的回调函数中,有花费长时间的计算。那么会阻塞node.js的事件轮询。

 

NodeJS中,他的高效,关键在于快速的返回事件循环。

 

我们将requestHandler.js改造如下,在这个例子中,由于事件循环一直被sleep函数阻塞着,导致createServer的callback无法及时返回。

 

function sleep(milliSecond) {
	
	var startTime = new Date().getTime();
	
	console.log(startTime);
	
	while(new Date().getTime() <= milliSecond + startTime) {
		
	}
	
	console.log(new Date().getTime());
}
exports.hello = function(res) {
        sleep(20000);
	res.writeHead(200, {"Content-Type": "text/plain"});
		
	res.write("say hello.");
		
	res.end();
};

exports.upload = function(res) {
	res.writeHead(200, {"Content-Type": "text/plain"});
	
	res.write("upload");
	
	res.end();
};

 

那么先键入http://localhost:8088/hello,后键入http://localhost:8088/upload。你会发现,upload虽然不需要花费太多时间,但是却要等到hello完成。

 

 

我们试图找寻异步调用的方法。比如formidable中的上传,经测试是非阻塞的。查看formidable的源码,发现最关键的是下面的代码:

IncomingForm.prototype.parse = function(req, cb) {
  this.pause = function() {
    try {
      req.pause();
    } catch (err) {
      // the stream was destroyed
      if (!this.ended) {
        // before it was completed, crash & burn
        this._error(err);
      }
      return false;
    }
    return true;
  };

  this.resume = function() {
    try {
      req.resume();
    } catch (err) {
      // the stream was destroyed
      if (!this.ended) {
        // before it was completed, crash & burn
        this._error(err);
      }
      return false;
    }

    return true;
  };

  this.writeHeaders(req.headers);

  var self = this;
  req
    .on('error', function(err) {
      self._error(err);
    })
    .on('aborted', function() {
      self.emit('aborted');
    })
    .on('data', function(buffer) {
      self.write(buffer);
    })
    .on('end', function() {
      if (self.error) {
        return;
      }

      var err = self._parser.end();
      if (err) {
        self._error(err);
      }
    });

  if (cb) {
    var fields = {}, files = {};
    this
      .on('field', function(name, value) {
        fields[name] = value;
      })
      .on('file', function(name, file) {
        files[name] = file;
      })
      .on('error', function(err) {
        cb(err, fields, files);
      })
      .on('end', function() {
        cb(null, fields, files);
      });
  }

  return this;
};

 

在parse中,将head信息解析出来这段是阻塞的。但是真正上传文件却是在req.on(data)中,是利用了事件驱动,是非阻塞的。也就是说,他的非阻塞模型依赖整个nodeJS事件分派架构。 

 

那么像sleep那样消耗大量计算,但是又不能依赖nodeJS分派架构的时候怎么办?

 

现在介绍一种,类似于html5 WebWorker的方法。

将requestHandler.js改造如下:

 

var childProcess = require("child_process");

exports.hello = function(res) {
	
	var n = childProcess.fork(__dirname + "/subProcess.js");
	
	n.on('message', function() {
		
		res.writeHead(200, {"Content-Type": "text/plain"});
		
		res.write("say hello.");
		
		res.end();	
	});
	
	n.send({});
};

exports.upload = function(res) {
	res.writeHead(200, {"Content-Type": "text/plain"});
	
	res.write("upload");
	
	res.end();
};

 

并加入subProcess.js

 

function sleep(milliSecond) {
	
	var startTime = new Date().getTime();
	
	console.log(startTime);
	
	while(new Date().getTime() <= milliSecond + startTime) {
		
	}
	
	console.log(new Date().getTime());
}

process.on('message', function() {
	sleep(20000);
	process.send({});
});

 

测试,当hello还在等待时,upload已经返回。

0
0
分享到:
评论
4 楼 rainsilence 2013-01-14  
glchen 写道
yaolifei 写道
你好,请教几个问题:
createServer的callback是阻塞的吗? 我以为每个请求的调用都不影响,不知道究竟是怎么样的过程。

还有一个问题,看你的代码应该是看了nodejs入门,我也看了,你那个hello里面的sleep导致upload也阻塞了可以说createServer是阻塞的。但是如果这样写:

function start(response) {
  console.log("Request handler 'start' was called.");

  exec("ls -lah", function (error, stdout, stderr) {
    response.writeHead(200, {"Content-Type": "text/plain"});
    response.write(stdout);
    response.end();
  });
}

exec这个应该是非阻塞的吧?那为什么我这样写:
function start(response) {
	console.log("Request handler 'start' was called.");
	
	exec('dir', function(error, stdout, stderr){
		function sleep(milliSeconds){
			var startTime = new Date().getTime();
			while (new Date().getTime() < startTime + milliSeconds);
		}
		sleep(10000);
		response.writeHead(200, {'Content-Type': 'text/plain'});	
		response.write(stdout);
		response.end();
	});
}

我把sleep放在非阻塞的方法里执行,应该也不会阻塞upload吧,但是还是会阻塞

话说要把sleep放在subProcess.js中的
process.on('message', function() { 
    sleep(20000); 
    process.send({}); 
});
这样才不会阻塞,我试了一晚上才发现的说...



html5 WebWorker也是一样的原理
3 楼 glchen 2013-01-13  
yaolifei 写道
你好,请教几个问题:
createServer的callback是阻塞的吗? 我以为每个请求的调用都不影响,不知道究竟是怎么样的过程。

还有一个问题,看你的代码应该是看了nodejs入门,我也看了,你那个hello里面的sleep导致upload也阻塞了可以说createServer是阻塞的。但是如果这样写:

function start(response) {
  console.log("Request handler 'start' was called.");

  exec("ls -lah", function (error, stdout, stderr) {
    response.writeHead(200, {"Content-Type": "text/plain"});
    response.write(stdout);
    response.end();
  });
}

exec这个应该是非阻塞的吧?那为什么我这样写:
function start(response) {
	console.log("Request handler 'start' was called.");
	
	exec('dir', function(error, stdout, stderr){
		function sleep(milliSeconds){
			var startTime = new Date().getTime();
			while (new Date().getTime() < startTime + milliSeconds);
		}
		sleep(10000);
		response.writeHead(200, {'Content-Type': 'text/plain'});	
		response.write(stdout);
		response.end();
	});
}

我把sleep放在非阻塞的方法里执行,应该也不会阻塞upload吧,但是还是会阻塞

话说要把sleep放在subProcess.js中的
process.on('message', function() { 
    sleep(20000); 
    process.send({}); 
});
这样才不会阻塞,我试了一晚上才发现的说...
2 楼 rainsilence 2012-06-05  
这个我准备专门写一篇文章来说明
1 楼 yaolifei 2012-06-04  
你好,请教几个问题:
createServer的callback是阻塞的吗? 我以为每个请求的调用都不影响,不知道究竟是怎么样的过程。

还有一个问题,看你的代码应该是看了nodejs入门,我也看了,你那个hello里面的sleep导致upload也阻塞了可以说createServer是阻塞的。但是如果这样写:

function start(response) {
  console.log("Request handler 'start' was called.");

  exec("ls -lah", function (error, stdout, stderr) {
    response.writeHead(200, {"Content-Type": "text/plain"});
    response.write(stdout);
    response.end();
  });
}

exec这个应该是非阻塞的吧?那为什么我这样写:
function start(response) {
	console.log("Request handler 'start' was called.");
	
	exec('dir', function(error, stdout, stderr){
		function sleep(milliSeconds){
			var startTime = new Date().getTime();
			while (new Date().getTime() < startTime + milliSeconds);
		}
		sleep(10000);
		response.writeHead(200, {'Content-Type': 'text/plain'});	
		response.write(stdout);
		response.end();
	});
}

我把sleep放在非阻塞的方法里执行,应该也不会阻塞upload吧,但是还是会阻塞

相关推荐

    NodeJs中的非阻塞方法介绍

    NodeJs中的非阻塞方法介绍,需要的朋友可以参考下

    nodejs-architecture-loopback-domain:使用REST架构模式和域的NodeJS 9非阻塞IO架构

    Node.js体系结构环回域使用环回和域层的NodeJS 9非阻塞I / O架构要求NodeJS 9以上堆JavaScript的6 回送3.x 回送启动2.x 回送资源管理器5.x 回送限制最大值1.x 回送MySQL 5.x环回企业架构在实际应用中,我们需要具有...

    nodejs中基于回调的非阻塞的读取文件例子

    通过异步处理大并发例子

    NodeJS API文档

    Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型。Node 是一个让 JavaScript 运行在服务端的开发平台,它让 JavaScript 成为与PHP、Python、Perl、Ruby 等服务端语言平起平坐的脚本语言。发布于2009年5月,由Ryan...

    nodejs-回调函数

    在这个例子中主要讲解 nodejs的回调函数,阻塞代码实例和非阻塞代码实例

    【JavaScript源代码】nodejs中的异步编程知识点详解.docx

     更进一步,nodejs引入了非阻塞的 I/O ,从而将异步的概念扩展到了文件访问、网络调用等。 今天,我们将会深入的探讨一下各种异步编程的优缺点和发展趋势。 在讨论nodejs的异步编程之前,让我们来讨论一个比较...

    NodeJS实现同步的方法

    NodeJS被打上了单线程、非阻塞、事件驱动…..等标签。 在单线程的情况下,是无法开启子线程的。经过了很久的研究,发现并没有thread函数!!!但是有时候,我们确实需要“多线程”处理事务。nodeJS有两个很基础的api...

    轻松创建nodejs服务器(8):非阻塞是如何实现的

    这节我们来了解一下nodejs实现非阻塞操作的方法。 我们先来修改一下 start的处理程序: 代码如下: var exec = require(“child_process”).exec; function start() {  console.log(“Request handler ‘start’ ...

    nodejs.rar

    Node.js 是一个开源与跨平台的 ... Node.js 在其标准库中提供了一组异步的 I/O 原生功能(用以防止 JavaScript 代码被阻塞),并且 Node.js 中的库通常是使用非阻塞的范式编写的(从而使阻塞行为成为例外而不是规范)。

    nodejs12140x64.zip

    Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型。 [1] Node 是一个让 JavaScript 运行在服务端的开发平台,它让 JavaScript 成为与PHP、Python、Perl、Ruby 等服务端语言平起平坐的脚本语言。 [2] 发布于2009...

    asyncj:使用 Future 模式或回调(NodeJS 风格)进行异步非阻塞编程的灵活而简单的库。 没有第三方依赖,没有重量级的包装器和类,没有废话,只需添加 maven 依赖并构建可扩展的应用程序

    灵活且超轻量级的库,用于使用 Future 模式、回调(NodeJS 风格)和异步非阻塞编程。 动机 该库的第一个目标是为 Java 8 提供模式的轻量级实现。此外,该库还提供对 Java 流水线的支持。 第二个目的是演示 Java 8 ...

    ​ nvm,全称 node.js version management,就是nodejs版本管理用具,nvm可以快速切换使用不用

    Node.js使用了一个事件驱动、非阻塞式I/O的模型( Node.js的特性),使其轻量级又高效 npm,Node Package Manager,nodejs 包管理工具。在安装的 nodejs 的时候,npm 也会跟着一起安装,它是包管理工具。npm 管理 ...

    nodejs安装包

    Node.js是一个基于Chrome JavaScript运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络...Node.js 使用事件驱动, 非阻塞I/O 模型而得以轻量和高效,非常适合在分布式设备上运行的数据密集型的实时应用。

    Nodejs中怎么实现函数的串行执行

    众所周知,nodejs是用非阻塞异步io机制,也就是说函数执行完成的先后顺序和代码的编写的先后顺序可能不同,实际的顺序取决于一个函数自身执行的快慢。这就出现一个在nodejs中怎么编写串行执行也就是顺序执行代码的...

    nodejs安装32位及64位

    Node.js是一个Javascript运行环境(runtime)。实际上它是对Google V8引擎进行了封装。...Node.js 使用事件驱动, 非阻塞I/O 模型而得以轻量和高效,非常适合在分布式设备上运行数据密集型的实时应用。

    win7 安装最后一个支持的nodejs-13.14.0.zip

    Node.js 使用高效、轻量级的事件驱动、非阻塞 I/O 模型。Node.js 的生态系统是目前最大的开源包管理系统。 Node.js 是一套用来编写高性能网络服务器的 JavaScript 工具包,一系列的变化由此开始。比较独特的是,...

    nodejs不错的文档

    Node.js是一个基于Chrome JavaScript运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络...Node.js 使用事件驱动, 非阻塞I/O 模型而得以轻量和高效,非常适合在分布式设备上运行的数据密集型的实时应用。

    NodeJs 10.14.1

    Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。 Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。

Global site tag (gtag.js) - Google Analytics