Node.js 回調函數

     回調:指的是將一個函數作爲參數傳遞給另外一個函數,並且通常在第一個函數執行完成以後被調用。把函數指針(地址)作爲參數傳遞給另一個函數,當這個指針被用來調用其所指向的函數時,我們就說這是回調函數。回調函數不是由該函數的實現方直接調用,而是在特定的事件或條件發生時由另外的一方調用的,用於對該事件或條件進行響應。Node.js 異步編程的直接體現就是回調,回調函數在完成任務後就會被調用,Node 使用了大量的回調函數,Node 所有 API 都支持回調函數。

    我們可以一邊讀取文件,一邊執行其他命令,在文件讀取完成後,我們將文件內容作爲回調函數的參數返回。這樣在執行代碼時就沒有阻塞或等待文件 I/O 操作。這就大大提高了 Node.js 的性能,可以處理大量的併發請求。

阻塞代碼實例

創建一個文件 foo.txt ,內容如下,注意保存的時候編碼爲UTF-8,這樣才能在後續Node.js 輸出中,顯示中文。

我在www.csdn.net 上寫博客

創建 main.js 文件(這裏也要保存爲UTF-8,不然顯示中文也是亂碼),代碼如下:

var fs = require("fs");
var data = fs.readFileSync('foo.txt');
console.log(data.toString());
node main.js
程序執行結束!
菜鳥教程官網地址:www.runoob.com

console.log("程序執行結束!");

以上代碼執行結果如下:

node main.js
 我在www.csdn.net 上寫博客
程序執行結束!

在程序調用執行node main.js的時候,這裏要注意將main,js 與foo.txt 文件放在同一個目錄下面,不然會因爲找不到foo.txt文件,而導致程序運行失敗。

在這個代碼中,我們可以看到程序先讀取foo.txt文件的內容,然後再輸出:程序執行結束!,如果foo.txt比較大,讀取會花費很多時間,後面的輸出會等待很長的時間,直到讀取文件完成,纔會執行下面的:程序執行結束!這就是阻塞的示例,必須要等到前面的動作執行完成。

非阻塞代碼實例

將剛纔的main.js 文件, 修改爲如下代碼:

var fs = require("fs");
fs.readFile('foo.txt', function (err, data) {
    if (err) return console.error(err);
    console.log(data.toString());
});
console.log("程序執行結束!");

以上代碼執行結果如下:

node main.js
<span class="pun">程序執行結束!</span>
 我在www.csdn.net 上寫博客

此時程序先輸出後面的:程序執行結束!,然後再輸出在foo.txt文檔中讀取的內容,以上的例子,並沒有等待foo.txt文件讀取完成,而是採用非阻塞的辦法,直接執行程序下面的代碼,我們可以執行讀取文件下面的內容,而不用去等待讀取文件的結束,這就是非阻塞。

以上兩個例子,我們可以看出,阻塞按是按順序執行的,而非阻塞是不需要按順序的,所以如果需要處理回調函數的參數,我們就需要寫在回調函數內。

當然如果在Node.js 中,我們需要採用阻塞的方式調用函數,那麼我們也可以通過在回調函數中嵌套回調函數即可。

    這裏同步和阻塞這兩個術語可以互換使用,指的是代碼的執行會在函數返回之前停止,就如在前面的示例所看到的,如果某個操作阻塞,那麼腳本就無法繼續。對於用戶而言,這就意味着必須等待。異步和非阻塞這兩個術語也可以相互互換,指的是基於回調的、允許腳本並行執行操作的方法。腳本無需等待某個操作的結果才能繼續前進,因爲操作結果會在事件發生時有回調來處理,使用異步方法,操作無需一個接一個地發生。

 

事件循環

  現在,讀者可能會問,這些神奇的事件是如何發生的?Node.js使用Javacript的事件循環來支持它所推崇的異步編程風格。這可能又是一個難以掌握的概念。基本上,事件循環使得系統可以將回調函數先保存起來,而後當事件在將來發生時再運行。這可以是數據庫返回數據,也可以是HTTP請求返回數據。因爲回調函數的執行被推遲到事件發生之後,於是,就無需停止執行,控制流可以返回到Node運行時的環境,從而讓其他事情繼續發生。如本文中所看到的阻塞和非阻塞示例那樣,使用事件虛幻是另外一種編程方式,有些開發人員稱其爲編程將裏面翻到外面的程序,實際上關鍵思想是,將代碼圍繞着事件來架構而不是按照期待中的輸入順序來架構,由於事件循環以單一進程爲基礎,所以爲了確保高新能需要遵循以下的規則:

1、函數必須快速返回。

2、函數不得阻塞。

3、長時間運行的操作必須移到另外一個進程中。

  在這樣的上下文中,有些程序不適合於事件循環,如果程序或函數需要長時間才能完成處理,那麼事件循環就不是一個好的選擇。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章