經過前面兩天的學習,已經對Node.js有了一個初步的認識,今天繼續學習其他內容,并加以整理分享,如有不足之處,還請指正,
回呼函式
1. 什么是回呼函式?
回呼函式,或簡稱回呼【callback】將一個A函式作為引數傳入另一個B函式中,B函式在執行程序中,根據時機或條件決定是否呼叫A函式,A函式就是B函式的回呼函式,
2. 回呼函式實作機制
回呼函式的實作機制如下所示:
- 定義一個回呼函式(普通函式);
- 將回到函式的參考地址作為引數傳遞給呼叫者;
- 當特定的事件或條件發生時,呼叫者使用函式指標呼叫回呼函式對事件進行處理,
3. 回呼函式用途
回呼函式在JavaScript中使用非常多,最簡單的場景就是事件注冊或異步函式,如:當用戶點擊某個按鈕時,需要做出相應的回應,那么就會用到回呼函式,
4. 回呼函式示例
以常用的setInterval為例,就是將show作為引數傳遞給setInverval,所以show就是setInterval的回呼函式,如下所示:
1 function show(){ 2 console.log("今天星期三,又是快樂的一天"); 3 } 4 setInterval(show,1000);
執行結果,如下所示:

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

異步與同步
1. 什么是異步與同步?
- 同步:一個任務等待前一個任務結束,然后再執行,程式的執行順序與任務的排列順序是一致的,同步的,
- 異步:每一個任務有一個或多個回呼函式(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的注意事項,如下所示:
- setTimeOut和setInterval兩個函式是同步執行,但是函式的回呼函式引數是定時器異步執行,
- setTimeOut和setInterval兩個函式的最小時間間隔為10-15ms,即使設定成0,也是如此,
- 異步函式的執行時間,永遠在同步執行完之后再執行,
關于主執行緒和任務執行緒的執行順序,可參考下圖:

異步的實作
在Node.js中,異步共有三種實作方式:
- 回呼函式,回呼函式不一定是異步,但是異步一定有回呼函式,
- 事件【基于回呼】
- 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物件有以下兩個特點:
- 物件的狀態不受外界影響,Promise物件代表一個異步操作,有三種狀態:Pending(進行中),Resolved(已完成,又稱FulFilled)和Rejected(已失敗),只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態,
- 一旦狀態改變,就不會再變,任何時候都可以得到這個結果,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可以通過訊息的傳遞,保證異步操作的順序,
備注
觀滄海【作者】曹操 【朝代】東漢末年/三國
東臨碣石,以觀滄海,水何澹澹,山島竦峙,
樹木叢生,百草豐茂,秋風蕭瑟,洪波涌起,
日月之行,若出其中;星漢燦爛,若出其里,
幸甚至哉,歌以詠志,
作者:小六公子
出處:http://www.cnblogs.com/hsiang/
本文著作權歸作者和博客園共有,寫文不易,支持原創,歡迎轉載【點贊】,轉載請保留此段宣告,且在文章頁面明顯位置給出原文連接,謝謝,
關注個人公眾號,定時同步更新技術及職場文章
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/445541.html
標籤:其他
