1. 程式人生 > 其它 >Node.js基礎入門第三天

Node.js基礎入門第三天

經過前面兩天的學習,已經對Node.js有了一個初步的認識,今天繼續學習其他內容,並加以整理分享,如有不足之處,還請指正。

回撥函式

1. 什麼是回撥函式?

回撥函式,或簡稱回撥【callback】將一個A函式作為引數傳入另一個B函式中,B函式在執行過程中,根據時機或條件決定是否呼叫A函式,A函式就是B函式的回撥函式。

2. 回撥函式實現機制

回撥函式的實現機制如下所示:

  1. 定義一個回撥函式(普通函式);
  2. 將回到函式的引用地址作為引數傳遞給呼叫者;
  3. 當特定的事件或條件發生時,呼叫者使用函式指標呼叫回撥函式對事件進行處理。

3. 回撥函式用途

回撥函式在JavaScript中使用非常多,最簡單的場景就是事件註冊或非同步函式。如:當用戶點選某個按鈕時,需要做出相應的響應,那麼就會用到回撥函式。

4. 回撥函式示例

以常用的setInterval為例,就是將show作為引數傳遞給setInverval,所以show就是setInterval的回撥函式,如下所示:

1 function show(){
2     console.log("今天星期三,又是快樂的一天");
3 }
4 setInterval(show,1000);

執行結果,如下所示:

 關於setInterval的引數說明,如下所示:

 

非同步與同步

1. 什麼是非同步與同步?

  1. 同步:一個任務等待前一個任務結束,然後再執行,程式的執行順序與任務的排列順序是一致的,同步的。
  2. 非同步:每一個任務有一個或多個回撥函式(callback),前一個任務結束後,不是執行後一個任務,而是執行回撥函式,後一個任務則是不等前一個任務結束就開始執行,所以程式的執行順序與任務的排列順序是不一致的,非同步的。

2. 同步示例

同步即按順序執行,存在先後順序,如下所示:

1 console.log("1111");
2 console.log("2222");
3 console.time("t1");
4 for(var i=0;i<1000000;i++){
5     
6 }
7 console.timeEnd("t1");
8 console.log("3333");

同步執行結果,如下所示:

3. 非同步示例一

非同步則是採用回撥函式執行,如下所示:

 1 console.log("1111");
 2 console.log("2222");
 3 setTimeout(function
(){ 4 console.time("t1"); 5 for(var i=0;i<1000000;i++){ 6 7 } 8 console.timeEnd("t1"); 9 },1000); 10 console.log("3333");

示例執行結果,如下所示:

 

4. 非同步示例二

即使主執行緒位於阻塞當中,非同步回撥函式也要等待主執行緒執行完成後再執行。如下所示:

 1 console.log("1111");
 2 console.log("2222");
 3 setTimeout(function(){
 4     console.log("2222-3333");
 5 },15);
 6 console.time("t1");
 7 for(var i=0;i<100000000;i++){
 8     
 9 }
10 console.timeEnd("t1");
11 console.log("3333");

示例執行結果

關於setTimeOut和setInterval的注意事項,如下所示:

  1. setTimeOut和setInterval兩個函式是同步執行,但是函式的回撥函式引數是定時器非同步執行。
  2. setTimeOut和setInterval兩個函式的最小時間間隔為10-15ms,即使設定成0,也是如此。
  3. 非同步函式的執行時間,永遠在同步執行完之後再執行。

關於主執行緒和任務執行緒的執行順序,可參考下圖:

 

非同步的實現

在Node.js中,非同步共有三種實現方式:

  1. 回撥函式,回撥函式不一定是非同步,但是非同步一定有回撥函式。
  2. 事件【基於回撥】
  3. Promise【ES6新增】

1. 回撥函式的同步示例

回撥函式也可能是同步的,如下所示:

1 console.log("1111");
2 var arr=[1,2,3,4];
3 arr.forEach(function(v,i){
4     console.log(v);
5 });
6 console.log("2222");

示例執行結果

 

2. 非同步事件示例

定義一個服務,當請求時,返回對應的資訊。如下所示:

 1 var http=require("http");
 2 var server=http.createServer();
 3 server.on('request',function(req,res){
 4     res.writeHead(200,{"Content-Type":'text/html;charset=utf-8'});
 5     res.write("<h1>你正在訪問小六子的伺服器</h1>");
 6     res.end();
 7 });
 8 server.listen(8080,function(){
 9     console.log("服務已啟動");
10 });

3. 非同步示例截圖

當服務啟動時,如下所示:

當發起請求時,返回資訊如下所示:

Promise基礎

1. 什麼是Promise ?

Promise(承諾)就是一個物件,用來傳遞非同步操作的訊息。它代表了某個未來才會知道的結果的事件(通常是一個非同步操作),並且這個事件提供統一的API,可供進一步處理。

2. Promise特點

Promise物件有以下兩個特點:

  1. 物件的狀態不受外界影響。Promise物件代表一個非同步操作,有三種狀態:Pending(進行中),Resolved(已完成,又稱FulFilled)和Rejected(已失敗)。只有非同步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。
  2. 一旦狀態改變,就不會再變,任何時候都可以得到這個結果。Promise物件的狀態改變,只有兩種可能:從Pending變為Resolved和從Pending變為Rejected。只要這兩種情況發生,狀態就不會再變了,會一直保持這種結果。如果改變已經發生了,你再對Promise物件添加回調函式,也會立即得到這個結果。這與事件(Event)完全不同,事件的特點是,如果你錯過了它,再去監聽,是得不到結果的。

3. 非同步的缺點

非同步的執行順序和時間是不可控的,如下所示:

假如現在有兩個檔案file1.txt,file2.txt,如下所示:

 

 

 

 這兩個檔案是有先後順序的,然後依次進行讀取,程式碼如下所示:

1 var fs =require("fs");
2 
3 fs.readFile("./file1.txt",function(err,data){
4     console.log(data.toString());
5 });
6 
7 fs.readFile("./file2.txt",function(err,data){
8     console.log(data.toString());
9 });

示例結果如下所示:

 

 通過以上示例不難發現,每次執行得到的結果不完全相同,有時與我們預期的結果並不一致,這就是非同步的不可控性。那麼如何解決呢?

4. Promise保證非同步順序

通過Promise可以保證非同步執行的順序,如下所示:

 1 var p1 = new Promise(function(resolve,reject){
 2     fs.readFile("./file1.txt",function(err,data){
 3         if(err){
 4             reject(err);
 5         }else{
 6             resolve(data.toString());
 7         }
 8     });
 9 });
10 
11 var p2 = new Promise(function(resolve,reject){
12     fs.readFile("./file2.txt",function(err,data){
13         if(err){
14             reject(err);
15         }else{
16             resolve(data.toString());
17         }
18     });
19 });
20 //通過陣列中的順序,控制非同步輸出的順序
21 Promise.all([p1,p2]).then(function(datas){
22     console.log(datas);
23 },function(errs){
24     console.log(errs);
25 });

優化後的結果,如下所示:

 

通過以上示例發現,Promise可以通過訊息的傳遞,保證非同步操作的順序。

備註

觀滄海【作者】曹操 【朝代】東漢末年/三國

碣石,滄海。澹澹,山島竦峙。

樹木叢生,百草豐茂。秋風蕭瑟,洪波湧起。

日月之行,若出其中;星漢燦爛,若出其裡。

甚至哉,以詠志。