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

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

標題寫的可能也不太對,你們領會精神;node

Node.js 是一個基於Chrome JavaScript 運行時創建的一個平臺。編程

Node.js是一個事件驅動I/O服務端JavaScript環境,基於Google的V8引擎,V8引擎執行Javascript的速度很是快,性能很是好。json

 

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 | 菜鳥教程

 

 

 

不不不,一點也不推薦你們這麼用。。。

太low了 用Promise吧

function run_a(num) {
  return new Promise(function (resolve, reject) {
    if (!isNaN(num)) {
      resolve({ "number": num, "10*num": 10 * num })
    } else {
      reject({ "error": num + " is not a number!" })
    }
  });
}

var array = [1, 2, 3, 4, 5, 6, 7];
var function_array = [];
array.forEach(element => {
  function_array.push(run_a(element));
});
console.log(function_array); // Array(7) [Promise, Promise, Promise, Promise, Promise, Promise, Promise]

Promise.all(function_array).then(function (data) {
  console.log(JSON.stringify(data));
  // [{"number":1,"10*num":10},{"number":2,"10*num":20},{"number":3,"10*num":30},{"number":4,"10*num":40},
  // {"number":5,"10*num":50},{"number":6,"10*num":60},{"number":7,"10*num":70}]
}, function (data) {
  console.log(data);
});
var array = [1, 2, 3, 4, 5, 'a', 7];
var function_array = [];
array.forEach(element => {
  function_array.push(run_a(element));
});

Promise.all(function_array).then(function (data) {
  console.log(JSON.stringify(data));
}, function (data) {
  console.log(data); // {error: "a is not a number!"}
});

Promise的用法簡單入門_慕課手記

用Promise應對這種未知次數的併發等待問題能夠說是很合適的了。

 

 

 

 

                                                                                                                                                                                            J.X.Duasonir

相關文章
相關標籤/搜索