回調函數在完成任務後就會被調用,Node 使用了大量的回調函數,Node 全部 API 都支持回調函數。javascript
異步讀取文件的回調函數:java
var fs = require("fs"); fs.readFile('input.txt', function (err, data) { if (err) return console.error(err); console.log(data.toString()); }); console.log("程序執行結束!");
Node.js 的每個 API 都是異步的node
Node.js 基本上全部的事件機制都是用設計模式中觀察者模式實現。設計模式
Node.js 單線程相似 進入一個while(true)的事件循環,直到沒有事件 觀察者退出,每一個異步事件都生成一個事件觀察者,若是有事件發生(觀察者)就調用該回調函數。異步
有點相似於觀察者模式,事件至關於一個主題(Subject),而全部註冊到這個事件上的處理函數至關於觀察者(Observer)。函數
var events = require('events');
var eventEmitter = new events.EventEmitter();
--------------------------------------------------------------------
// 方法1.採用handler函數 // 建立事件處理程序 var connectHandler = function connected() { console.log('鏈接成功'); // step 1 eventEmitter.emit('data_received'); // 這裏觸發 step 2 } // 綁定 connection 事件處理程序 eventEmitter.on('connection', connectHandler);
--------------------------------------------------------------------
// 方法2.採用匿名函數(或者箭頭函數) // 使用匿名函數綁定 data_received 事件 eventEmitter.on('data_received', function(){ console.log('數據接收成功'); // step 2 }); // 觸發 connection 事件 eventEmitter.emit('connection'); // 這裏觸發 step 1 console.log("程序執行完畢。"); // step 3
//event.js 文件 var events = require('events'); var emitter = new events.EventEmitter();
emitter.on('someEvent', function(arg1, arg2) { console.log('listener1', arg1, arg2); }); emitter.on('someEvent', function(arg1, arg2) { console.log('listener2', arg1, arg2); }); emitter.emit('someEvent', 'arg1 參數', 'arg2 參數');
當事件觸發時,註冊到這個事件的事件監聽器被依次調用,事件參數做爲回調函數參數傳遞。ui
$ node event.js
listener1 arg1 參數 arg2 參數
listener2 arg1 參數 arg2 參數
//event.js 文件 var EventEmitter = require('events').EventEmitter; var event = new EventEmitter(); event.on('some_event', function() { console.log('some_event 事件觸發'); });
setTimeout(function() { event.emit('some_event'); }, 1000);
順便提一個:間隔觸發spa
setInterval ( ); --> clearInterval(timer); 線程
<script type="text/javascript"> window.onload = function () { var count = 0; var bt = document.getElementById("bt"); function show(){ document.getElementById("ant").innerHTML = count + 1; count = count +1; } var flag = setInterval(show, 1000); bt.onclick = function () { clearInterval(flag); } } </script>
一個綜合性的例子:設計
var events = require('events'); var eventEmitter = new events.EventEmitter();
// (1) 定義監聽回調方法 // 監聽器 #1 var listener1 = function listener1() { console.log('監聽器 listener1 執行。'); } // 監聽器 #2 var listener2 = function listener2() { console.log('監聽器 listener2 執行。'); }
// (2) 兩種綁定監聽器到事件上 // 綁定 connection 事件,處理函數爲 listener1 eventEmitter.addListener('connection', listener1); // 綁定 connection 事件,處理函數爲 listener2 eventEmitter.on('connection', listener2);
var eventListeners = require('events').EventEmitter.listenerCount(eventEmitter,'connection'); console.log(eventListeners + " 個監聽器監聽鏈接事件。");
// (3) 觸發事件發生 // 處理 connection 事件 eventEmitter.emit('connection');
// (4) 去掉監聽器 // 移除監綁定的 listener1 函數 eventEmitter.removeListener('connection', listener1); console.log("listener1 再也不受監聽。"); // 觸發鏈接事件 eventEmitter.emit('connection'); eventListeners = require('events').EventEmitter.listenerCount(eventEmitter,'connection'); console.log(eventListeners + " 個監聽器監聽鏈接事件。"); console.log("程序執行完畢。");
EventEmitter 定義了一個特殊的事件 error,它包含了錯誤的語義,遇到 異常的時候一般會觸發 error 事件。
當 error 被觸發時,EventEmitter 規定若是沒有響 應的監聽器,Node.js 會把它看成異常,退出程序並輸出錯誤信息。
咱們通常要爲會觸發 error 事件的對象設置監聽器,避免遇到錯誤後整個程序崩潰。例如:
var events = require('events'); var emitter = new events.EventEmitter(); emitter.emit('error');
大多數時候咱們不會直接使用 EventEmitter,而是在對象中繼承它。包括 fs、net、 http 在內的,只要是支持事件響應的核心模塊都是 EventEmitter 的子類。
爲何要這樣作呢?緣由有兩點:
Person類自己會有多個有意義的對象,好比:xiaoming, lili, lucy。
但願他們對同一個事件都會有相似的反應,好比老師喊報名,各自起來報本身姓名。
故,這裏觸發事件speak綁定在每個person身上。
以後,觸發了xiaoming的神經;觸發了lucy的神經。