1. 程式人生 > 實用技巧 >學習nodejs中的事件和迴圈。

學習nodejs中的事件和迴圈。

與此相關的建議:nodejs教程
對於熟悉javascript的朋友,應該會使用一些事件,例如滑鼠移動、滑鼠點選、鍵盤輸入等。通過監聽javascript中的這些事件,我們可以觸發相應的處理。
事件存在於相同的nodejs中,並且有一個專門的events模組用於特殊處理。
在nodejs中,事件和事件迴圈是構建非同步IO的重要概念。
現在我們來做個詳細的介紹。
活動。
nodejs提供了用於事件的專用模組:lib/events.js。
記住,我們說過要用nodejs構建web伺服器。
配置伺服器=http.createServer((req,res)=>{
res.statuscode=200。
res.setHeader(“文字/序言型別”)
end('welcometowww.flydean.com)
')
})
其中,請求事件由每個請求觸發。
Nodejs的核心API是基於非同步事件驅動的體系結構,因此nodejs中存在大量事件。
例如:net.Server每當有新連線時都會觸發事件,fs.ReadStream則在檔案開啟時觸發,而stream則在資料可讀時觸發。
看看如何為nodejs構建事件吧:
constEventEmitter=require(中心)
consteventEmitter=新的事件EventEmitter()
vents的常用方法有兩種,on和emit。
on用於監聽事件,emit用於觸發該事件。
eventEmitter.on('fire')=>{
Console.log(點火)
})
Emitter.emit('fire')
emit也可以使用引數,我們來看看下一個:
eventEmitter.on('fire',who=>{
console.log(${who}) }) eventEmitter.emit('fire','美帝') 看一下另外兩個引數: eventEmitter.on('fire'(who,when)=>{ (

射擊${who}${when})console.log }) eventEmitter.emit('fire','川的建國','now') 預設情況下,EventEmitter按註冊順序同步呼叫所有監聽器。這確保了事件的正確排序,並且有助於避免競爭狀態和邏輯錯誤。 如果需要非同步執行,您可以使用setImmediate()或process.nextTick()將其切換為非同步執行模式。 eventEmitter.on('fire'(who,when)=>{ setImmediate()=>{ console.log(射擊${who}${when});
});
})
eventEmitter.emit('fire','川的建國','now')
除了這些,events還支援其他一些方法:
once():新增一個單獨的監聽器。
removeListener()/off():將事件監聽器從事件中刪除。
removeAllListeners():為事件刪除所有監聽器。
活動迴圈。
據我們所知,nodejs的程式碼執行在單執行緒環境中,每次只能處理一件事情。
這種處理方式避免了多執行緒環境下的資料同步問題,大大提高了處理效率。
稱為事件迴圈,是指處理器在一個程式週期內,處理完一個週期的事件後,將進入下一個週期,處理下一個週期的事情,這樣,一個週期的事件將進入下一個週期。
阻止事件迴圈。
在事件處理期間,如果某個事件的處理被阻塞,那麼其他事件的執行將受到影響,因此可以看到JS中幾乎所有的IO都是非阻塞的。這就是javascript中回撥函式如此之多的原因。
活動週期舉例
下面看看一個簡單的迴圈事件示例:
2=()=>console.log('action2')
3=()=>console.log('action3')
配置1=()=>{
Console.log('action1')
動作2()
動作3()
}
操作1()
上述程式碼輸出:
動作1。
動作2。
動作3。
棧和訊息佇列。
在上面的示例中,我們知道函式之間的呼叫是通過棧實現的,並且我們的呼叫順序也是通過棧實現的。
但是,並非函式中的所有方法都會進入棧,而其他方法則會進入訊息佇列。
下面還有另一個例子:
2=()=>console.log('action2')
3=()=>console.log('action3')
配置1=()=>{
Console.log('action1')
Setimeout(action2,0)
操作3()
}
操作1()
上述程式碼執行結果:
動作1。
動作3。
動作2。
情況有所不同。由於settimeout觸發了計時器,當計時器過期時,回撥函式將被放在訊息佇列中等待處理,而不是放在棧中。
當棧中沒有任何資料時,事件迴圈將優先處理棧中的事件,並將轉至消耗訊息佇列中的事件。
儘管上例中setTimeout的timeout時間為0,但在完成action3之前仍需等待。
請注意,setTimeout中的timeout不在當前執行緒中等待,瀏覽器或其他JS執行環境將呼叫該執行緒。
任務佇列和代理列表。
Promise在ES6中引入了作業佇列的概念,使用作業佇列將盡可能快地執行非同步功能的結果,而不是把它放在呼叫堆疊的末尾。
舉例來說:
2=()=>console.log('action2')
3=()=>console.log('action3')
配置1=()=>{
Console.log('action1')
Setimeout(action2,0)
新專案計劃((恢復,恢復)=>。
resolve(“應該在動作3之後,動作2之前”)
(a).then(resolve=>console.log)
動作3()
}
操作1()
產出:
動作1。
動作3。
應在動作3之後,動作2之前。
動作2。
原因在於resolve的Promise在當前函式結束前將在該函式之後立即執行。
也就是,首先執行棧,然後是作業佇列,最後是訊息佇列。
(c)process.nextTick
nextTick(()=>{
log('iamthenexttick');
})
因此,nextTick必須快於訊息佇列的setTimeout。
SetImmediate()
為了儘快執行程式碼,nodejs提供了setImmediate方法。
setImmediate()=>{
log('Iamimmediate!');
})
在setImmediate中的函式將在下一次事件迴圈中執行。
setImmediate()和setTimeout(()=>{},0)具有基本相似的功能。他們都將在事件迴圈的下一次迭代中執行。
setInterval()
如果您希望定時執行某些回撥函式,您需要使用setInterval。
SetInterval(()=>{
console.log(每2秒執行一次);
},2000)
使用clearInterval,可以清除以上定時任務:
Constid=setInterval()=>{
console.log(每2秒執行一次);
},2000)
clearInterval(ID)
請注意,setInterval是每隔n毫秒啟動一個函式,無論它完成與否。
當一個函式執行得太久,導致下一個函式同時執行時,如何來解決這個問題?
可考慮在回撥函式中再次呼叫setTimeout,從而形成一個遞迴的setTimeout呼叫:
配置=()=>{{
console.log('完成後,隔天執行2次!');
Setimeout(MyFunction,2000年)
}
Setimeout(MyFunction,2000年)