浅谈node的异步

Posted fandaxia

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈node的异步相关的知识,希望对你有一定的参考价值。

 

    刚和朋友吃完饭,回来接着写  ,异步,是node 中一个很重要的概念,可以说对于前端想要转到后台的来说(我这里说的是没有接触过后台的人来说),路由和异步还有包括node是如何建立web服务呈递页面的,这些东西很难转变过来,特别对于经常写js的人来说,来做node的话,可能经常就分不清楚哪里写的是前端代码,那些写的是后台代码了,这是思维模式方面的转变,这个的确很难,特别如果前端接触一段时间node会特别有感触。

   我本人最早是学。net后台的,之后慢点接触前端,学习js的一些技术,包括一些框架jquery,ng(angular等)还有bootstrap等,之后接触到的node,对于我来说node中最大的不同之处就是在异步这一块,node中的很多东西基本都是异步的,所以如果你不理解异步的话,很难深入学习node,可以说,这也是node思想的精髓所在,不然node的单线程是无法实现高并发的,所以想要学node,异步必须要了解。

    其实我之前写的用fs模块读取html文件的时候,这个fs模块的读取文件的过程就是异步的,当node遇到一个I/O的时候,他不会停下等这个I/O操作网,再去执行其他代码,而是继续去执行别的代码,等到I/O操作完成),会触发执行完的事前,调用执行完成时的回调函数,所以在这里我们也可以理解node中的事件驱动,event loop,非阻塞I/O等概念了。

    其实在咱们之前学的js中,就有异步的概念,我在ajax异步简介这篇随笔中还提到了的,那么咱们可以简单的看下异步的原理

    

var a=1;
setTimeout(function(){
	console.log(a);//2
}, 30000);
console.log(a);//1
a++;

  从上面可以看出,当js遇到定时器的时候,上面settimeout定时器定义了一个定时器,3秒后触发内面的方法,当js遇到这个定时器的时候,js不会到这里停3秒,等到定时器里的方法触发,而是继续执行下面的代码,等到3秒到后,触发执行定时器内的方法,上面这个例子可以简单的理解下异步的概念(不一定严谨,哈哈)。

      当然这是js中的异步的一个简单案例,可以这么说node的牛逼的地方很大程度上在于异步上,刘邦说,成也萧何,败也萧何。。那么我们也可以说node成也异步,败也异步(当然node还是很厉害的哈,至少在移动端盛行的今天,高并发的时后,node还是发挥了很重要的作用,手机淘宝听说在上层就是用的node来处理高并发的,当然业务层可能是php,底层可能还是java和mysql等),好了,咱们回归正题。

     我之前说道,如果是老牌语言的后台来学node,其他都很好理解,就是异步这块特别别扭,因为业务始终是同步的,而在node中很多操作都是异步执行,这可能会导致某个业务会有很多层的嵌套,在代码层面就是一层回调套一层回调,回调里面在套回调,这样从老牌后台语言转到node的人,就会感觉特别扭,而且业务复杂了后,代码将也会很复杂(但是根本还是思想的转变)。

     好,我们来看下这样的一个例子(看下node的异步)

   

var http = require(‘http‘);
var fs = require(‘fs‘);

var server = http.createServer(function(req,res){
	//我们做这样一个场景,模仿用户同时登录系统,看看node中关于事件执行的机制和异步的I/O
	//从这个中可以看到node中事件是如何工作,node是如何在单线程的条件下有高度的并发的特点的
    var randomNum = Math.random()*1000 + 3212;
    console.log(‘欢迎用户user_‘+randomNum);
    fs.readFile(‘test/1.txt‘,function(err,data){
    	console.log(‘用户_user‘+randomNum+‘读取完毕‘);

    })
    res.end();
});
server.listen(3010,‘127.0.0.1‘);

  我们然后不断的刷新浏览器,观察控制台中的输出,

技术分享图片

很明显我们看到了,显示欢饮用户4119后没有立马显示4119读取完毕,而是欢迎用户3776,然后再是用户4119读取文件,所以这里我们很明显可以看到这里的异步操作,用户4119读取文件时,服务并没有阻塞,而是继续相应用户3776的请求,所以这就是node的非阻塞I/O,这也是node能够实现高并发的依赖。

上述例子我们看到了fs的读取数据的过程是异步的,所以我们要获取读取文件的信息,就必须在fs的回调函数中写代码,这和我之前在。net或php中的做法完全不同,在。net或php中都是通过摸个对象或方法,输入文件路径,和其他参数,然后返回给你一个字符串(文本的数据);

 技术分享图片

 

  看到这样一个api,于是直接撸代码,开干(app.js)

var fs = require(‘fs‘);

fs.readdir(‘./album‘,function(err,files){
	if(err){
		//获取目录下的文件信息失败
		return;
	}
	//获取目录下的所有文件成功,files中包含了album文件夹下所有的文件信息
	var directorys = [];
	for (var i = 0; i < files.length; i++) {
		var file = files[i];
		fs.stat(‘./album/‘+file,function(err,stats){
			if(stats.isDirectory()){
				//是一个文件夹
				directorys.push(files[i]);
				console.log(directorys);
			}
		})
	};

	
})

  

输出

技术分享图片

很明显,这不是我们想要的结果,那么为什么会出现两个undefined的情况列,如果我们好好想想就明白了,fs模块的操作是异步的,而我在这里再for循环中嵌套了fs的操作,所以还没等fs的操作完成,for循环就搞完了,这样最后得到的i的值就是length,超出了files的界限了,files【i】自然就是=undefined。但是这几本就是老牌后台程序员的思维,所以我才认为这是对由其他后台转node的,需要转变的思维的地方。(我之前也晕了好久,但是慢点多写点就好了)

  那么正确的及解决方案是怎样的了,我在这里使用的是立即函数+递归实现类似于迭代器的功能,来实现的(简单的说,就是强行将异步转变同步,),上代码体会就懂了话不多说

var fs = require(‘fs‘);

fs.readdir(‘./album‘,function(err,files){
	if(err){
		//获取目录下的文件信息失败
		return;
	}
	//获取目录下的所有文件成功,files中包含了album文件夹下所有的文件信息
	var directorys = [];
	/*for (var i = 0; i < files.length; i++) {
		var file = files[i];
		fs.stat(‘./album/‘+file,function(err,stats){
			if(stats.isDirectory()){
				//是一个文件夹
				directorys.push(files[i]);
				console.log(directorys);
			}
		})
	};*/

	(function getDirectory(i){
		if(i == files.length){
			//读取完毕
			console.log(directorys);
			return;
		}
		var file = files[i];
		fs.stat(‘./album/‘+file,function(err,stats){
			if(stats.isDirectory()){
				//是一个文件夹
				directorys.push(files[i]);
			}
			getDirectory(i+1);
		})
	})(0)
})

  

 

 输出

 

 技术分享图片

纵欲得到了正确的结果,真的是太艰辛了,当然上面这种用立即函数的形式在前端中也经常会看到,这是我的解决方式,虽然,node中也有同步方法,在node的官网可以看到,node在很多异步操作的后面都要提供了相应的同步的操作,但是我始终感觉,node这样做,是不是与自己的理念有点背道而驰(当然了,个人见解,高手勿喷,哈哈哈哈)。。

这就是我自己对异步的一点理解,当然我的理解都是从代码层面上来说明的,可能有点浅显(个人能力尚浅),我感觉只有理解好这些后,才能保证你的node代码继续写下去,继续学下去,否则很可能学到一定程度你就想地放弃node了,(因为前端用node可能更多的用来构建前端自动化和包管理方面),等你真真涉及后台的一些思想和技术时,你就会发现有很大的不同的

 

 

   

以上是关于浅谈node的异步的主要内容,如果未能解决你的问题,请参考以下文章

浅谈Node.js单线程模型

浅谈Node.js单线程模型

浅谈JS异步(asychrouous)

浅谈JavaScript中的异步处理

浅谈Ajax 异步的几点细节

浅谈.Net异步编程的前世今生----TPL篇