nodejs筆記之:事件驅動,線程池,非阻塞,異常處理等
2016年05月01日 14:44:42 Johnny丶me 閱讀數 4112更多
分類專欄: NodeJs Nodejs 硬實戰 全棧工程師筆記
版權聲明:本文爲博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接:https://blog.csdn.net/Tyro_java/article/details/51290419
事件驅動:
事件驅動的模型:
事件驅動的原理:
原理總結:
Nodejs 會把所有請求和異步操作都放到一個事件隊列中,用戶的每一個請求就是一個事件。主線程先把普通代碼執行完畢,然後會循環事件隊列裏的函數,如果遇到有IO的操作,nodejs會去線程池裏拿出一個線程去執行IO的操作,執行完畢後再把拿到數據的回調函數,放到事件隊列的尾部,繼續事件循環。
線程池
線程池的概念:
Node是單線程的,這裏的單線程僅僅是javascript執行在單線程中,V8引擎不支持io操作,在node中,無論是類unix還是windows平臺內部完成IO的操作都有線程池。
在windows下,node實現IO異步的解決方案是iocp:調用異步方法,等待IO完成之後的通知,執行回調,用戶無需考慮輪詢,但是其內部仍然是線程池原理,不同之處在於這些線程池是由系統內核接受管理。
在linux下,0.9.3版本之前的node是使用libeio配合libuv實現的異步IO,在此版本之後的node自行實現了線程池來完成異步io操作。
本質上nodejs 是個多線程平臺。如果有io操作,nodejs交給 中間層libuv去做,它的底層就是C或者C++來實現的,所以nodejs本質上還是個多線程平臺。
IO 操作
io操作就是以流的形式,進行的操作,比如網絡請求,文件讀取寫入。io操作也就是input和output的操作。
阻塞IO
在調用阻塞io時,應用程序需要等待io完成才能返回結果。
阻塞io的特點:調用之後一定要等到系統內核層面完成所有操作之後,調用才結束。
阻塞io造成CUP等待IO,浪費等待時間,CPU的處理能力不能得到充分利用。
非阻塞IO
爲了提高性能,內核提供了非阻塞io,非阻塞io跟阻塞io的差別是調用之後會立即返回。
阻塞io完成整個獲取數據的過程,而非阻塞io則不帶數據直接返回,要獲取數據,還要通過問價你描述符再次讀取。
非阻塞io返回之後,cpu時間片可以用來處理其他事物,此時性能提升非常明顯。
Nodejs中的異常處理
Node是單線程運行環境,一旦拋出異常,沒有被處理,就會引起整個進程崩潰。
Node的異常處理,對於保證系統穩定運行非常重要。
Node有三種方式,處理一個錯誤 :
1. throw 拋出異常。
2. 將錯誤對象傳遞給回調函數,由回調函數負責處理錯誤。
3. 使用try catch捕獲異常有時候會不及時,合理的放置 trycath 去捕獲,在異步內部,而不是在異步的外層去捕獲,就像是下面的在回調函數內部去try catch 。
回調函數
Node採用: 將錯誤對象作爲第一個參數傳入回調函數,這樣就避免了捕獲錯誤與發生錯誤不在一個時間段上的問題。
回調函數的設計
對於一個函數需要定義回調函數,node統一規定:
-
回調函數一定作爲參數的最後一個參數出現:
Function foo(arg1,arg2,callback){}
- 1
-
回調函數的第一個參數默認接收錯誤對象,第二個參數纔是真正的回調函數(便於外界獲取調用的錯誤情況)
// 執行一個doRead() 函數,假設有這麼一個函數,主要看裏面的異常處理 doRead(obj,function(err,res){ if(err) throw err; // err 是錯誤對象 console.log(res); // res 是具體的結果或者數據 } )
- 1
- 2
- 3
- 4
- 5
-
強調錯誤優先
- 錯誤優先的回調函數,第一個參數是上一步的錯誤對象
-
通過判斷回調函數中的err是否爲null,來檢測異步操作過程是否出現錯誤,我們用下面的例子來舉例說明:
const fs = require('fs'); // 定義一個讀文件函數 function readFile(path, callback) { fs.readFile(path, 'utf8', function (err, data) { if (err) { return callback(err, null); } callback(null, '輸出的數據爲:' + data); }); } readFile('./data/index.html', function (err, data) { if (err) { throw err; } console.log(data); });
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
總結:
- Node規定,如果某個函數需要作爲參數,則回調函數是最後一個參數,另外,回調函數本身的第一個參數,約定爲上一步傳入的錯誤對象
- 傳統的錯誤捕捉機制try catch,儘量不要使用,在異步操作中容易出錯。
- 一旦異步操作發生錯誤,就把錯誤對象傳遞到回調函數,如果沒有發生錯誤,回調函數的第一個參數就是null,如果不是null,就肯定出錯了。