nodejs之异步思想
2013-12-05 14:33
316 查看
nodejs的精髓就是"异步",但什么是异步呢?我们来看一个例子:
按照"Java"编程的思维习惯,应该是行1处定义了一个Date类型的变量,然后500毫秒后在显示 "Time elapsed:500 ms",再然后不断的输出"hello world!",持续大约500毫秒吧。
事实上不是这个样子的,当执行到行2时,发现了一个延时函数setTimeout,这时候呢,node不会停止执行,而是把这个函数放到了一个事件列表中,继续执行以后的代码,一直等到了所有的东西都处理完了,然后JavaScript虚拟机才会问 "队列里还有谁啊",然后再顺序的处理事件,这就是JS的一个很重的的特性。参考《JavaScript异步编程》。
知道了是一回事,但真正理解了又是另一回事。
对数据库的增删改查是最经常的操作了,下面咱就来开发一个往mysql的一个表person插入一条数据的小功能。代码如下:
代码很简单,在user.prototype.save函数里呢,我们调用了getId(),以得到最大的id+1来当作新id,然后保存到数据库里。好像很简单,没什么问题,那我们来做个测试吧:
运行一下看看:
在user代码的38行处显示了id为4,但怎么又报了 id cannot be null呢?
还是异步特性在作怪!!
我们来看看user.js的代码:
在13行处,我们获得了id号,然后把它放到新的行里的id里面。问题是"这个id真的存在了吗?"
在30行处的db.server.query里有个回调函数,这个回调函数是什么呢,它是执行完了这个查询后的返回结果!!!在没有执行完的时候呢,js虚拟机会继续运行程序,先运行40行,把未赋值的id返回了,继续往先走,走到14行,吧这个赋值的id当作了要插入行的主键,所以就会显示了报的错误。其实归根结底还是我们的同步思维。在getId函数里,我们想当然的认为id在37行处一定会被赋值!其实根据一开始讲到的,它肯定不会被赋值,因为在这个回调函数执行之前,先要去查询db,然后cpu是不会等待结果返回的,它一定会继续向下执行!
那我们该怎么办呢?难道对于这种事件依赖类型的需求,nodejs无法满足我们吗?要是连这点需求都做不到,估计nodejs还没被我们所知道之前就"夭折"了。
既然我们无法在拿到id之后执行下一步的操作,那就拿到它之后再操作不就行了!没错,就是把插入操作放到getId函数的回调函数里面去。如下所示:
这样把save操作放到了getId()方法的回调函数里面来完成了,所以nodejs的思路就从
得到A的结果进行B运算变成了进行A,并在A的回调函数里面进行B运算。要是还有依赖B节点的操作呢?没错,就是在B的回调函数里写操作呗。难改网上很多人抱怨nodejs回调函数太多,不好阅读了!
那有没有解决这个问题的办法呢,且待下次分解吧。
var start =new Date; setTimeout(function(){ var end =new Date; console.log('Time elapsed:', end - start, 'ms'); }, 500); while (new Date - start < 1000) { console.log("hello world!<br/>"); };
按照"Java"编程的思维习惯,应该是行1处定义了一个Date类型的变量,然后500毫秒后在显示 "Time elapsed:500 ms",再然后不断的输出"hello world!",持续大约500毫秒吧。
事实上不是这个样子的,当执行到行2时,发现了一个延时函数setTimeout,这时候呢,node不会停止执行,而是把这个函数放到了一个事件列表中,继续执行以后的代码,一直等到了所有的东西都处理完了,然后JavaScript虚拟机才会问 "队列里还有谁啊",然后再顺序的处理事件,这就是JS的一个很重的的特性。参考《JavaScript异步编程》。
知道了是一回事,但真正理解了又是另一回事。
对数据库的增删改查是最经常的操作了,下面咱就来开发一个往mysql的一个表person插入一条数据的小功能。代码如下:
var db = require('./db'); db.connectionReady(db.server); function user(name,birthday,password){ this.name = name; this.birthday = birthday; this.password = password; } module.exports = user; user.prototype.save = function(){ var id = getId(); db.server.query('INSERT INTO person SET id=?,name=?,birthday=?,password=?', [id,this.name,this.birthday,this.password], function(error,results){ if(error){ console.log('ClientReady Error:'+error.message); db.server.end(); return; } }); } getId=function(){ var id; var n = this.name; var b = this.birthday; var p = this.password; db.server.query('select count(*) from person', function(error,results,fields){ if(error){ console.log('ClientReady Error:'+error.message); db.server.end(); return; } id = parseInt(results[0]['count(*)'])+1; console.log("id=: "+id); }); return id; }
代码很简单,在user.prototype.save函数里呢,我们调用了getId(),以得到最大的id+1来当作新id,然后保存到数据库里。好像很简单,没什么问题,那我们来做个测试吧:
var User = require('./user'); var user = new User('zhangsan','1986-04-23','123'); user.save();
运行一下看看:
在user代码的38行处显示了id为4,但怎么又报了 id cannot be null呢?
还是异步特性在作怪!!
我们来看看user.js的代码:
在13行处,我们获得了id号,然后把它放到新的行里的id里面。问题是"这个id真的存在了吗?"
在30行处的db.server.query里有个回调函数,这个回调函数是什么呢,它是执行完了这个查询后的返回结果!!!在没有执行完的时候呢,js虚拟机会继续运行程序,先运行40行,把未赋值的id返回了,继续往先走,走到14行,吧这个赋值的id当作了要插入行的主键,所以就会显示了报的错误。其实归根结底还是我们的同步思维。在getId函数里,我们想当然的认为id在37行处一定会被赋值!其实根据一开始讲到的,它肯定不会被赋值,因为在这个回调函数执行之前,先要去查询db,然后cpu是不会等待结果返回的,它一定会继续向下执行!
那我们该怎么办呢?难道对于这种事件依赖类型的需求,nodejs无法满足我们吗?要是连这点需求都做不到,估计nodejs还没被我们所知道之前就"夭折"了。
既然我们无法在拿到id之后执行下一步的操作,那就拿到它之后再操作不就行了!没错,就是把插入操作放到getId函数的回调函数里面去。如下所示:
getId=function(){ var n = this.name; var b = this.birthday; var p = this.password; db.server.query('select count(*) from person', function(error,results,fields){ if(error){ console.log('ClientReady Error:'+error.message); db.server.end(); return; } var id = parseInt(results[0]['count(*)'])+1; db.server.query('INSERT INTO person SET id=?,name=?,birthday=?,password=?', [id,this.name,this.birthday,this.password], function(error,results){ if(error){ console.log('ClientReady Error:'+error.message); db.server.end(); return; } }); }); }
这样把save操作放到了getId()方法的回调函数里面来完成了,所以nodejs的思路就从
得到A的结果进行B运算变成了进行A,并在A的回调函数里面进行B运算。要是还有依赖B节点的操作呢?没错,就是在B的回调函数里写操作呗。难改网上很多人抱怨nodejs回调函数太多,不好阅读了!
那有没有解决这个问题的办法呢,且待下次分解吧。
相关文章推荐
- node express ejs 怎么使用layout
- 翻译--Blazing fast node.js: 10 performance tips from LinkedIn Mobile
- CCSpriteBatchNode
- 5分钟搭建一个HTML5视频聊天Demo(WebRTC+NodeJS)
- NODE.JS Class: stream.Readable
- 翻译--Blazing fast node.js: 10 performance tips from LinkedIn Mobile
- Node.js 中文学习资料和教程导航
- 【干货分享】Node.js 中文学习资料和教程导航
- nodejs创建项目
- javascript(Nodejs)中的一些实用小技巧
- 【mark】有关node.js的图片插件 node-images 在 ubuntu 12.04 安装不上的解决方案
- Hadoop 2.2 Single-Node Setup
- SHUTDOWN_MSG: Shutting down NameNode at java.net.UnknownHostException: xxx
- DataNode数据块工作流DataXceiver
- ubuntu的iNode的安装
- CCSpriteBatchNode的特点和使用方法
- nodeschool.io 4
- nodeschool.io 3
- nodeschool.io 2
- node express