使用events.EventEmitter 控制Node.js 程序執行流程
使用events.EventEmitter 控制Node.js 程序執行流程
標題寫的可能也不太對,大家領會精神;
Node.js 是一個基於Chrome JavaScript 運行時建立的一個平臺。
Node.js是一個事件驅動I/O服務端JavaScript環境,基於Google的V8引擎,V8引擎執行Javascript的速度非常快,性能非常好。
Node.js 異步編程的直接體現就是回調。
異步編程依托於回調來實現,但不能說使用了回調後程序就異步化了。
回調函數在完成任務後就會被調用,Node 使用了大量的回調函數,Node 所有 API 都支持回調函數。
例如,我們可以一邊讀取文件,一邊執行其他命令,在文件讀取完成後,我們將文件內容作為回調函數的參數返回。
這樣在執行代碼時就沒有阻塞或等待文件 I/O 操作。這就大大提高了 Node.js 的性能,可以處理大量的並發請求。
Node.js 是單進程單線程應用程序,但是因為 V8 引擎提供的異步執行回調接口,通過這些接口可以處理大量的並發,所以性能非常高。
Node.js 幾乎每一個 API 都是支持回調函數的。
Node.js 基本上所有的事件機制都是用設計模式中觀察者模式實現。
Node.js 單線程類似進入一個while(true)的事件循環,直到沒有事件觀察者退出,每個異步事件都生成一個事件觀察者,如果有事件發生就調用該回調函數。
大意就是說:與大多數 代碼從上至下線性執行的 程序不同,Node.js 程序不會“等”,
當程序執行到需要I/O執行時間的回調函數時,會主動略過等待,繼續執行下面的代碼;
因此就會出現一種弊端:一個特定函數的輸入(參數),是數個回調函數的返回;
程序的執行機制會略過 對回調函數的等待,直接執行下面的特定函數;此時特定函數並沒有等到回調函數返回的輸入;
例子如下:
var fs = require("fs");
var array = [1, 2, 3, 4, 5]; var json = {};
for (let index = 0; index < array.length; index++) { const element = array[index]; deal(element,function (ret) { json[element] = ret; console.log(json); }); } console.log(json); function deal(num, callback) { fs.readFile(num + ‘.txt‘, function (err, data) { if (err) { console.error(err); callback(err); } else { callback(data.toString().trim()); } }); } Object {} Object {1: "11111"} Object {1: "11111", 5: "55555"} Object {1: "11111", 3: "33333", 5: "55555"} Object {1: "11111", 3: "33333", 4: "44444", 5: "55555"} Object {1: "11111", 2: "22222", 3: "33333", 4: "44444", 5: "55555"}
回調函數要以數組裏的內容作為文件名,讀取文件中的數據作為返回值;
但程序不會等待文件讀取完成,在沒有一個文件讀取完畢的情況下就執行了打印操作,輸出了空對象;
如果想要按順序線性執行文件讀取,在讀取完畢後打印輸出,不僅浪費時間,而且一層套一層代碼冗余,
還無法預估數組大小(回調函數個數)。
Node.js 所有的異步 I/O 操作在完成時都會發送一個事件到事件隊列。
解決的辦法是:Node.js 的事件驅動特性,讓打印作為一個事件,在所有的回調函數執行完後,再觸發打印操作;
var fs = require("fs"); var events = require(‘events‘); var emitter = new events.EventEmitter(); var array = [1, 2, 3, 4, 5]; var count = 0; var json = {}; for (let index = 0; index < array.length; index++) { const element = array[index]; deal(element, function (ret) { json[element] = ret; console.log(json); }); } emitter.on(‘dataBack‘, function() { count ++; if(count == array.length){ console.log(json); } }); function deal(num, callback) { fs.readFile(num + ‘.txt‘, function (err, data) { if (err) { console.error(err); callback(err); emitter.emit(‘dataBack‘); } else { callback(data.toString().trim()); emitter.emit(‘dataBack‘); } }); } Object {1: "11111"} Object {1: "11111", 4: "44444"} Object {1: "11111", 3: "33333", 4: "44444"} Object {1: "11111", 3: "33333", 4: "44444", 5: "55555"} Object {1: "11111", 2: "22222", 3: "33333", 4: "44444", 5: "55555"} Object {1: "11111", 2: "22222", 3: "33333", 4: "44444", 5: "55555"}
在程序中添加打印事件和事件觸發,全部數據都集齊後再打印,
雖然還有count的鎖不鎖的問題存在,但實際的問題已然解決;
嗯嗯。
引用和改寫的程序都來源於 Node.js 教程 | 菜鳥教程
Node.js 文件系統 | 菜鳥教程
Node.js EventEmitter | 菜鳥教程
J.X.Duasonir
使用events.EventEmitter 控制Node.js 程序執行流程