nodejs之異步思想


nodejs的精髓就是"異步",但什么是異步呢?我們來看一個例子:

1 var start =new Date; 
2 setTimeout(function(){ 
3 var end =new Date; 
4     console.log('Time elapsed:', end - start, 'ms'); 
5 }, 500); 
6 while (new Date - start < 1000) {
7     console.log("hello world!<br/>");
8 }; 

按照"Java"編程的思維習慣,應該是行1處定義了一個Date類型的變量,然后500毫秒后在顯示 "Time elapsed:500 ms",再然后不斷的輸出"hello world!",持續大約500毫秒吧。

事實上不是這個樣子的,當執行到行2時,發現了一個延時函數setTimeout,這時候呢,node不會停止執行,而是把這個函數放到了一個事件列表中,繼續執行以后的代碼,一直等到了所有的東西都處理完了,然后JavaScript虛擬機才會問 "隊列里還有誰啊",然后再順序的處理事件,這就是JS的一個很重的的特性。參考《JavaScript異步編程》。

  知道了是一回事,但真正理解了又是另一回事。

 對數據庫的增刪改查是最經常的操作了,下面咱就來開發一個往mysql的一個表person插入一條數據的小功能。代碼如下:

 1 var db = require('./db');
 2 
 3 db.connectionReady(db.server);
 4 
 5 function user(name,birthday,password){
 6     this.name = name;
 7     this.birthday = birthday;
 8     this.password = password;
 9 }
10 
11 module.exports = user;
12 user.prototype.save = function(){
13     var id = getId();
14     db.server.query('INSERT INTO person SET id=?,name=?,birthday=?,password=?',
15         [id,this.name,this.birthday,this.password],
16     function(error,results){
17         if(error){
18             console.log('ClientReady Error:'+error.message);
19             db.server.end();
20             return;
21         }
22     });
23 }
24 
25 getId=function(){
26     var id;
27     var n = this.name;
28     var b = this.birthday;
29     var p = this.password;
30     db.server.query('select count(*) from person',
31         function(error,results,fields){
32             if(error){
33                 console.log('ClientReady Error:'+error.message);
34                 db.server.end();
35                 return;
36             }
37             id = parseInt(results[0]['count(*)'])+1;
38             console.log("id=: "+id);
39         });
40     return id;
41 }

代碼很簡單,在user.prototype.save函數里呢,我們調用了getId(),以得到最大的id+1來當作新id,然后保存到數據庫里。好像很簡單,沒什么問題,那我們來做個測試吧:

1 var User = require('./user');
2 
3 var user = new User('zhangsan','1986-04-23','123');
4 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函數的回調函數里面去。如下所示:

     

  

 1 getId=function(){
 2     var n = this.name;
 3     var b = this.birthday;
 4     var p = this.password;
 5     db.server.query('select count(*) from person',
 6         function(error,results,fields){
 7             if(error){
 8                 console.log('ClientReady Error:'+error.message);
 9                 db.server.end();
10                 return;
11             }
12             var id = parseInt(results[0]['count(*)'])+1;
13             db.server.query('INSERT INTO person SET id=?,name=?,birthday=?,password=?',
14             [id,this.name,this.birthday,this.password],
15             function(error,results){
16                 if(error){
17                     console.log('ClientReady Error:'+error.message);
18                     db.server.end();
19                     return;
20                 }
21                });
22         });
23 }

這樣把save操作放到了getId()方法的回調函數里面來完成了,所以nodejs的思路就從

得到A的結果進行B運算變成了進行A,並在A的回調函數里面進行B運算。要是還有依賴B節點的操作呢?沒錯,就是在B的回調函數里寫操作唄。難改網上很多人抱怨nodejs回調函數太多,不好閱讀了!

那有沒有解決這個問題的辦法呢,且待下次分解吧。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM