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回调函数太多,不好阅读了!

那有没有解决这个问题的办法呢,且待下次分解吧。

nodejs之异步思想的更多相关文章

  1. NodeJS的异步编程风格

    NodeJS的异步编程风格 http://www.infoq.com/cn/news/2011/09/nodejs-async-code NodeJS运行环境因其支持Javascript语言和异步编程 ...

  2. nodejs中异步

    nodejs中的异步 1 nodejs 中的异步存在吗? 现在有点 javascript 基础的人都在听说过 nodejs ,而只要与 javascript 打交到人都会用或者是将要使用 nodejs ...

  3. NodeJS示例异步式(Asynchronous)IO与同步式Synchronous)IO

    理解IO      IO(Input/Output)通常是指计算机线程进行慈磁盘读写或者网络通信时的一种行为.   同步式(Synchronous)IO和异步式(Asynchronous )IO   ...

  4. 深入理解nodejs的异步IO与事件模块机制

    node为什么要使用异步I/O 异步I/O的技术方案:轮询技术 node的异步I/O nodejs事件环 一.node为什么要使用异步I/O 异步最先诞生于操作系统的底层,在底层系统中,异步通过信号量 ...

  5. 深入剖析Nodejs的异步IO

    前言:Nodejs最赖以自豪的优势莫过于"单线程实现异步IO"了,也许你仍然丈二和尚摸不着头脑,Nodejs自我标榜是单线程,还能实现异步IO操作,这两者难道不是相互矛盾的么?葫芦 ...

  6. [nodejs] 同步/异步创建多层目录

    背景 有时项目里需要同时创建多层目录的功能,但低版本的nodejs并没有提供快捷的api 尽管在v10.12.0版本 mkdir() 第二个参数支持recursive 参数,为true时能递归创建,但 ...

  7. nodeJs 调试异步程序追踪异步报错

    DeprecationWarning: Calling an asynchronous function without callback is deprecated. 翻译: 不建议在不回调的情况下 ...

  8. nodejs的异步非阻塞IO

    简单表述一下:发启向系统IO操作请求,系统使用线程池IO操作,执行完放到事件队列里,node主线程轮询事件队列,读取结果与调用回调.所以说node并非真的单线程,还是使用了线程池的多线程. 上个图看看 ...

  9. Nodejs 处理异步(获取异步数据并处理)的方法

    方法1. 回调函数方式 将异步方法如readFile封装到一个自定义函数中,通过将异步方法得到的结果传给自定义方法的回调函数参数.具体如下(以fs模块的readFile方法为例): //封装 var ...

随机推荐

  1. Js文件中文乱码

    aspx页面引用的js文件中如果包括中文,中文显示乱码或者引起脚本错误.提示是'未结束的字符串' 原因:aspx页面的默认编码是utf-8,而js文件的默认编码是gb2312,两者之间不一致引起了中文 ...

  2. 数据库mysql优化方案

    1.创建索引对于查询占主要的应用来说,索引显得尤为重要.很多时候性能问题很简单的就是因为我们忘了添加索引而造成的,或者说没有添加更为有效的索引导致.如果不加索引的话,那么查找任何哪怕只是一条特定的数据 ...

  3. Android笔记:DrawerLayout抽屉布局的使用

    DrawerLayout(抽屉布局),在各种app中经常出现,比如csdn.. 如下示,只要从屏幕侧边滑一下,或者点击左上角的图标,抽屉就会出来. DrawerLayout要点: 1.使用Drawer ...

  4. selenium第二课(脚本录制seleniumIDE的使用)

    一.Selenium也具有录制功能,可以web中回放,录制的脚本可以转换为java.python.ruby.php等多种脚本语言.seleniumIDE是Firefox的一个插件,依附于Firefox ...

  5. jQuery Mobile 图标

    jQuery 图标 如需在 jQuery Mobile 中向按钮添加图标,请使用 data-icon 属性: <a href="#anylink" data-role=&qu ...

  6. Python之字符串小代码解析

    本篇只是拿一段代码来对python中的字符串的一些使用做解释,来让大家更加了解python Python 3.4.0 (v3.4.0:04f714765c13, Mar 16 2014, 19:25: ...

  7. [z]查表空间使用情况

    SELECT UPPER(F.TABLESPACE_NAME) "表空间名",D.TOT_GROOTTE_MB "表空间大小(M)",D.TOT_GROOTTE ...

  8. CSS盒子模型的理解

    标准的CSS盒子模型包括:内容(content).填充(padding).边框(border).边界(margin) 这些属性,可以把它转移到我们日常生活中的盒子(箱子)上来理解,日常生活中所见的盒子 ...

  9. 【CodeVS1076】排序

    Description 给出n和n个整数,希望你从小到大给他们排序 Input 第一行一个正整数n 第二行n个用空格隔开的整数 Output 输出仅一行,从小到大输出n个用空格隔开的整数 Sample ...

  10. 深入浅出: Java回调机制(异步)

    一.什么是回调 回调,回调.要先有调用,才有调用者和被调用者之间的回调.所以在百度百科中是这样的: 软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用.回调和异步调用. 回调 ...