真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

nodejs中怎么實現(xiàn)事件和事件循環(huán)

這期內(nèi)容當(dāng)中小編將會給大家?guī)碛嘘P(guān)nodejs中怎么實現(xiàn)事件和事件循環(huán),文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

創(chuàng)新互聯(lián)公司服務(wù)項目包括泰興網(wǎng)站建設(shè)、泰興網(wǎng)站制作、泰興網(wǎng)頁制作以及泰興網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,泰興網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到泰興省份的部分城市,未來相信會繼續(xù)擴大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!

事件

nodejs為事件提供了一個專門的模塊:lib/events.js。

還記得我們在講使用nodejs構(gòu)建web服務(wù)器嗎?

const server = http.createServer((req, res) => {
  res.statusCode = 200
  res.setHeader('Content-Type', 'text/plain')
  res.end('welcome to www.flydean.com\n')
})

這里,每個請求都會觸發(fā)request事件。

nodejs的核心API是基于異步事件驅(qū)動來進行架構(gòu)的,所以nodejs中有非常多的事件。

比如:net.Server 會在每次有新連接時觸發(fā)事件,fs.ReadStream 會在打開文件時觸發(fā)事件,stream會在數(shù)據(jù)可讀時觸發(fā)事件。

我們看一下怎么來構(gòu)建一個nodejs的事件:

const EventEmitter = require('events')
const eventEmitter = new EventEmitter()

events常用的方法有兩個,分別是on和emit。

on用來監(jiān)聽事件,emit用來觸發(fā)事件。

eventEmitter.on('fire', () => {
  console.log('開火')
})

eventEmitter.emit('fire')

emit還可以帶參數(shù),我們看下一個參數(shù)的情況:

eventEmitter.on('fire', who => {
  console.log(`開火 ${who}`)
})

eventEmitter.emit('fire', '美帝')

再看看兩個參數(shù)的情況:

eventEmitter.on('fire', (who, when) => {
  console.log(`開火 ${who} ${when}`)
})

eventEmitter.emit('fire', '川建國','now')

默認情況下,EventEmitter以注冊的順序同步地調(diào)用所有監(jiān)聽器。這樣可以確保事件的正確排序,并有助于避免競態(tài)條件和邏輯錯誤。

如果需要異步執(zhí)行,則可以使用setImmediate() 或者 process.nextTick()來切換到異步執(zhí)行模式。

eventEmitter.on('fire', (who, when) => {
    setImmediate(() => {
      console.log(`開火 ${who} ${when}`);
  });
})

eventEmitter.emit('fire', '川建國','now')

除此之外,events還支持其他幾個方法:

once(): 添加單次監(jiān)聽器

removeListener() / off(): 從事件中移除事件監(jiān)聽器

removeAllListeners(): 移除事件的所有監(jiān)聽器

事件循環(huán)

我們知道nodejs的代碼是運行在單線程環(huán)境中的,每次只會去處理一件事情。

這一種處理方式,避免了多線程環(huán)境的數(shù)據(jù)同步的問題,大大的提升了處理效率。

所謂事件循環(huán),就是指處理器在一個程序周期中,處理完這個周期的事件之后,會進入下一個事件周期,處理下一個事件周期的事情,這樣一個周期一個周期的循環(huán)。

事件循環(huán)的阻塞

如果我們在事件處理過程中,某個事件的處理發(fā)生了阻塞,則會影響其他的事件的執(zhí)行,所以我們可以看到在JS中,幾乎所有的IO都是非阻塞的。這也是為什么javascript中有這么多回調(diào)的原因。

事件循環(huán)舉例

我們看一個簡單的事件循環(huán)的例子:

const action2 = () => console.log('action2')

const action3 = () => console.log('action3')

const action1 = () => {
    console.log('action1')
    action2()
    action3()
}

action1()

上面的代碼輸出:

action1
action2
action3

棧和消息隊列

我們知道函數(shù)間的調(diào)用是通過棧來實現(xiàn)的,上面的例子中,我們的調(diào)用順序也是通過棧來實現(xiàn)的。

但并不是函數(shù)中所有的方法都會入棧,還有一些方法會被放入消息隊列。

我們再舉一個例子:

const action2 = () => console.log('action2')

const action3 = () => console.log('action3')

const action1 = () => {
    console.log('action1')
    setTimeout(action2, 0)
    action3()
}

action1()

上面的代碼運行結(jié)果:

action1
action3
action2

結(jié)果不一樣了。這是因為settimeout觸發(fā)了定時器,當(dāng)定時器到期的時候,回調(diào)函數(shù)會被放入消息隊列中等待被處理,而不是放入棧中。

事件循環(huán)會優(yōu)先處理棧中的事件,只有棧中沒有任何數(shù)據(jù)的時候,才會去轉(zhuǎn)而消費消息隊列中的事件。

雖然上面例子中setTimeout的timeout時間是0,但是還是要等到action3執(zhí)行完畢才能執(zhí)行。

注意,setTimeout中的timeout并不是在當(dāng)前線程進行等待的,它是由瀏覽器或者其他JS執(zhí)行環(huán)境來調(diào)用的。

作業(yè)隊列和promise

ES6中的Promise引入了作業(yè)隊列的概念,使用作業(yè)隊列將會盡快地執(zhí)行異步函數(shù)的結(jié)果,而不是放在調(diào)用堆棧的末尾。

舉個例子:

const action2 = () => console.log('action2')

const action3 = () => console.log('action3')

const action1 = () => {
    console.log('action1')
    setTimeout(action2, 0)
    new Promise((resolve, reject) =>
        resolve('應(yīng)該在action3之后、action2之前')
    ).then(resolve => console.log(resolve))
    action3()
}

action1()

輸出結(jié)果:

action1
action3
應(yīng)該在action3之后、action2之前
action2

這是因為,在當(dāng)前函數(shù)結(jié)束之前 resolve 的 Promise 會在當(dāng)前函數(shù)之后被立即執(zhí)行。

也就是說先執(zhí)行棧,再執(zhí)行作業(yè)隊列,最后執(zhí)行消息隊列。

process.nextTick()

先給大家一個定義叫做tick,一個tick就是指一個事件周期。而process.nextTick()就是指在下一個事件循環(huán)tick開始之前,調(diào)用這個函數(shù):

process.nextTick(() => {
  console.log('i am the next tick');
})

所以nextTick一定要比消息隊列的setTimeout要快。

setImmediate()

nodejs提供了一個setImmediate方法,來盡快的執(zhí)行代碼。

setImmediate(() => {
  console.log('I am immediate!');
})

setImmediate中的函數(shù)會在事件循環(huán)的下一個迭代中執(zhí)行。

setImmediate() 和 setTimeout(() => {}, 0)的功能基本上是類似的。它們都會在事件循環(huán)的下一個迭代中運行。

setInterval()

如果想要定時執(zhí)行某些回調(diào)函數(shù),則需要用到setInterval。

setInterval(() => {
  console.log('每隔2秒執(zhí)行一次');
}, 2000)

要清除上面的定時任務(wù),可以使用clearInterval:

const id = setInterval(() => {
  console.log('每隔2秒執(zhí)行一次');
}, 2000)

clearInterval(id)

注意,setInterval是每隔n毫秒啟動一個函數(shù),不管該函數(shù)是否執(zhí)行完畢。

如果一個函數(shù)執(zhí)行時間太長,就會導(dǎo)致下一個函數(shù)同時執(zhí)行的情況,怎么解決這個問題呢?

我們可以考慮在回調(diào)函數(shù)內(nèi)部再次調(diào)用setTimeout,這樣形成遞歸的setTimeout調(diào)用:

const myFunction = () => {
  console.log('做完后,隔2s再次執(zhí)行!');

  setTimeout(myFunction, 2000)
}

setTimeout(myFunction, 2000)

上述就是小編為大家分享的nodejs中怎么實現(xiàn)事件和事件循環(huán)了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。


當(dāng)前題目:nodejs中怎么實現(xiàn)事件和事件循環(huán)
新聞來源:http://weahome.cn/article/godpeg.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部