`
rainsilence
  • 浏览: 160554 次
  • 性别: 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中的非阻塞方法介绍

    ### Node.js中的非阻塞方法介绍 #### 一、引言 Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。它通过单线程和事件驱动的架构来处理并发请求,使得 Node.js 在执行 I/O 密集型任务时能够表现出较高的...

    nodejs中实现阻塞实例

    对于I/O密集型的操作,使用异步操作可以有效提升性能,而CPU密集型的操作,如果不希望阻塞事件循环,也应该采用异步或非阻塞的方式处理,或者考虑将其迁移到多线程或集群环境中运行。 在实际开发中,推荐在处理异步...

    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让异步变成同步的方法

    Node.js中让异步操作变成同步的方法通常是指将非阻塞的异步调用改写为在逻辑上表现得像同步调用的方式。Node.js中异步操作是通过回调函数、Promises和async/await等技术来实现的。以下我们详细讲解如何通过这些方法...

    NodeJS 安装包

    在实际开发中,NodeJS 的非阻塞 I/O 模型使得它非常适合处理大量的并发连接,例如在实时聊天应用、流媒体服务或者游戏服务器等场景下。同时,由于 JavaScript 语法在客户端和服务器端的一致性,NodeJS 也促进了前后...

    NodeJS API文档

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

    NodeJS示例

    NodeJS 具有非阻塞 I/O、事件驱动的特性,使得它在处理高并发请求时表现出色。它还拥有丰富的生态系统,包括 npm(Node Package Manager),提供了大量的第三方模块,可以方便地扩展功能。在实际开发中,NodeJS 常...

    nodejs中英文文档合集及chm打包

    1. **基础教程**:这部分内容会介绍如何安装Node.js,解释Node.js的核心特性,如非阻塞I/O和事件驱动模型,以及如何创建第一个Node.js应用。 2. **API文档**:涵盖Node.js内置模块的详细说明,如文件系统(fs)、...

    NodeJS整理手册文档

    NodeJS的基础知识包括安装与环境配置、模块系统、事件驱动模型和非阻塞I/O。NodeJS的模块系统采用CommonJS规范,使得代码可复用性高,便于组织大型项目。事件驱动模型是NodeJS的核心,通过事件循环机制处理并发请求...

    NodeJS学习笔记和代码

    1. **事件驱动模型**:NodeJS的核心特性之一是其事件驱动非阻塞I/O模型,这使得NodeJS在处理大量并发连接时表现优秀。 2. **模块系统**:NodeJS使用CommonJS模块规范,通过`require`引入模块,`exports`或`module....

    NodeJS-技术讲解

    2. I/O 阻塞: NodeJS 通过非阻塞 I/O 模型解决了 I/O 阻塞的问题。 NodeJS 的优缺点: 优点: 1. 高并发(最重要的优点,据说可以应付百万级并发) 2. 适合 I/O 密集型应用 缺点: 1. 不适合 CPU 密集型应用...

    NodeJS C++,打印机模块源码

    6. **异步处理**:为了保持NodeJS的非阻塞特性,C++模块可能使用回调、Promise或者async/await来处理异步打印任务。 7. **测试和示例**:项目可能包含测试脚本来验证模块的功能,以及示例JavaScript代码展示如何在...

    NodeJS开发指南_nodejs开发指南_

    NodeJS的核心是事件驱动、非阻塞I/O模型,这使得它在处理高并发请求时表现优秀。其单线程执行和异步编程的特点,让开发者能够构建高效的网络应用程序。 1. 安装与环境配置:NodeJS的安装过程相对简单,可以在官网...

    NodeJS介绍

    - **非阻塞I/O的优势**:非阻塞I/O机制使得NodeJS能够在不等待I/O操作完成的情况下继续执行其他任务,从而提高了整体的响应速度。 - **长连接的支持**:NodeJS能够很好地支持长连接,这对于实时通信应用非常重要。 ...

    七天学会NodeJS

    - **实时通信**:利用NodeJS的非阻塞I/O模型,可以轻松实现聊天应用、在线游戏等实时交互功能。 - **微服务架构**:NodeJS轻量级的特点非常适合构建微服务架构中的各个服务组件。 - **桌面和移动应用**:通过框架如...

    NodeJs教程含NodeJS API介绍(中文版)

    另外,非阻塞I/O模型也是Node.js的特色之一,通过回调函数、Promise或者async/await来实现。 文件系统模块fs是Node.js中的重要部分,提供了一系列方法用于读取、写入、创建、删除和操作文件和目录。例如,fs....

    NodeJS的特点概述

    3. **非阻塞I/O**:非阻塞I/O模型使得NodeJS在处理I/O密集型任务时特别高效。这意味着当一个I/O操作被发起时,NodeJS不会等待结果返回,而是继续执行其他任务。 4. **轻量且高效**:因为NodeJS采用了非阻塞I/O模型...

Global site tag (gtag.js) - Google Analytics