nodejs筆記之:事件驅動,線程池,非阻塞,異常處理等

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統一規定:

  1. 回調函數一定作爲參數的最後一個參數出現:

    Function foo(arg1,arg2,callback){}
    • 1
  2. 回調函數的第一個參數默認接收錯誤對象,第二個參數纔是真正的回調函數(便於外界獲取調用的錯誤情況)

    // 執行一個doRead() 函數,假設有這麼一個函數,主要看裏面的異常處理
    doRead(obj,function(err,res){
        if(err) throw err; // err 是錯誤對象
        console.log(res); // res 是具體的結果或者數據
     } )
    • 1
    • 2
    • 3
    • 4
    • 5
  3. 強調錯誤優先

    • 錯誤優先的回調函數,第一個參數是上一步的錯誤對象
    • 通過判斷回調函數中的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

總結:

  1. Node規定,如果某個函數需要作爲參數,則回調函數是最後一個參數,另外,回調函數本身的第一個參數,約定爲上一步傳入的錯誤對象
  2. 傳統的錯誤捕捉機制try catch,儘量不要使用,在異步操作中容易出錯。
  3. 一旦異步操作發生錯誤,就把錯誤對象傳遞到回調函數,如果沒有發生錯誤,回調函數的第一個參數就是null,如果不是null,就肯定出錯了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章