由尼爾·洛博,軟體工程師
Node.js 的流行部分是事件迴圈。Node.js 使用事件驅動的非阻塞 I/O 模型,而不是採用傳統框架的多線程方法。這使其記憶體佔用量更輕,更輕巧、更高效,並針對數據密集型即時應用擴展良好。
此事件驅動的非阻塞方法適用於瓶頸為 I/O 或網路活動的應用程式。相反,如果應用程式需要 CPU 密集型任務,則 Node.js 可能是一個糟糕的選擇。
但是,使用裸節點.js 需要使用非同步回調,從而導致臭名昭著的回調地獄。這導致邏輯難以遵循
//Callback Soup/Spiral Callback of Doom function doAsync1(function () { doAsync2(function () { doAsync3(function () { doAsync4(function () { //finally do something }); }); }); });
錯誤處理和嵌套回調在編寫時不太舒服,並且它們的存在使得代碼難以維護和擴展。有一些技術來克服這些問題,最流行的是纖維和承諾。 我想討論前者,因為 Meteor 使用光纖在事件迴圈上實現同步代碼。
纖維
對於那些不熟悉它的人來說,光纖是一個計算機科學結構,它使用協作多任務模型(不像線程使用先發制人的多任務處理)
線程代碼可能隨時中斷,即使在評估表達式時也是如此,以便為在另一個線程中運行的代碼提供 CPU 週期。對於光纖,這些中斷和上下文開關不是由 CPU 或較低級別的進程決定的;它們由程式師決定,由他們決定他的代碼將產生在哪裡,並給其他光纖的CPU週期。
下面是典型的 Node.js 代碼的範例,該代碼使用傳遞結果的回調函數。
取得資料從磁碟=函數(檔案名、金鑰、回檔功能){
var 結果;
fs.readFile('/path/fileName', function(err, res) { if (err) console.log(err); else { result = transform(res, key); callbackFunction(result); }}};
讓我們以更同步的樣式來編寫
getDataFromDisk = function(fileName, key) { var result; fs.readFile('/path/fileName', function(err, res) { if (err) console.log(err); else result = transform(res, key);
} 傳回結果;//將始終未定義 }; 我們嘗試使用 getDataFromDisk 傳回值,然後 列印出來,全部同步列印。 var 結果 = 獲取數據從磁碟("helloWorld",鍵); 控制台.log(結果); 定義
上述代碼將始終返回未定義,因為事件循環將移動到返回結果行 (*),而無需等待回調的結果。
使用光纖
光纖是一類容器函數,可用於在等待某些 I/O 或網路活動時阻止子例程,而不會阻止整個過程。
var Fiber = Npm.require('fibers');// getDataFromDisk function using Fibers getDataFromDisk = function(filename, key) {var fiber = Fiber.current; //get the current Fiber fs.readFile('/path/fileName', function(err, res) { if (err) console.log(err); else{ /* Resume execution of this fiber. What’s passed to fiber.run will become the value returned by Fiber.yield below */ fiber.run( transform(res, key) ); var result = Fiber.yield(); return result;}; // Finally we wrap our code in a Fiber, then run it Fiber(function() {
var 結果 = 獲取數據從Disk('helloWorld',鍵); 控制台.log(結果); *)運行();
Presto,我們有同步查找代碼,這些代碼仍在事件迴圈上異步運行。
有關光纖的更多詳細資訊,請查看 (https://github.com/laverdet/node-fibers)