1. 程式人生 > >使用events.EventEmitter 控制Node.js 程序執行流程

使用events.EventEmitter 控制Node.js 程序執行流程

html 文件系統 bsp () googl round 命令 文件中 all

使用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 程序執行流程