nodejs中如何實現(xiàn)事件循環(huán),很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
成都創(chuàng)新互聯(lián)公司堅信:善待客戶,將會成為終身客戶。我們能堅持多年,是因為我們一直可值得信賴。我們從不忽悠初訪客戶,我們用心做好本職工作,不忘初心,方得始終。10余年網(wǎng)站建設經(jīng)驗成都創(chuàng)新互聯(lián)公司是成都老牌網(wǎng)站營銷服務商,為您提供網(wǎng)站建設、網(wǎng)站制作、網(wǎng)站設計、H5網(wǎng)站設計、網(wǎng)站制作、高端網(wǎng)站設計、成都微信小程序服務,給眾多知名企業(yè)提供過好品質(zhì)的建站服務。
process.nextTick()不在event loop的任何階段執(zhí)行,而是在各個階段切換的中間執(zhí)行;即從一個階段切換到下個階段前執(zhí)行;
三種定義異步事件的方式: setTimeout,setImmediate,process.nextTick()
var fs = require('fs'); fs.readFile(__dirname,() =>{ setTimeout(() =>{ console.log('setTimeout') }) setImmediate(() =>{ console.log('setImmediate') process.nextTick(() =>{ console.log('nextTick3') }) }) process.nextTick(() =>{ console.log('nextTick1') }) process.nextTick(() =>{ console.log('nextTick2') }) }) // nextTick1 nextTick2 setImmediate nextTick3 setTimeout
在多個事件交叉執(zhí)行cpu運算密集型的任務
var http = require('http'); function compute(){ process.nextTick(compute) } http.createServer(function(req,res){ // 服務請求的時候,還能抽空進行一些計算任務; res.writeHead(200, {'Content-type': 'text/plain'}) res.end('hello world'); }) compute()
在這種模式下,我們不需要遞歸的調(diào)用compute(),我們只需要在事件循環(huán)中使用process.nextTict()定義;compute()在下一個事件點執(zhí)行即可;在這個過程中,如果有新的http請求進來,事件循環(huán)機制會先處理新的請求,然后再調(diào)用copute().反之,如果把compute()放在一個遞歸里調(diào)用,那系統(tǒng)一直會阻塞在compute()里,無法處理新的http請求了。
保持回調(diào)函數(shù)異步執(zhí)行的原則
當給一個函數(shù)定義一個回調(diào)函數(shù)時,要確保這個回調(diào)是異步執(zhí)行的(定義一個callback,但是又需要在callback里面使用這個變量);
下面示例違反了這一原則:
function asyncFake(data,callback){ // 同步執(zhí)行 if(data === 'foo') callback(true) else callback(false) } asyncFake('bar',function(result){ // this callback is actually called synchronously! })
為什么這樣不好呢?看下面nodejs文檔里的一段代碼
var client = net.connect(8124, function(){ console.log('client connect'); client.write('world'); // 會報錯 })
在上面的代碼里,如果因為某種原因,net.connect()變成同步執(zhí)行的了,回調(diào)函數(shù)就會立刻被執(zhí)行,因此回調(diào)函數(shù)寫到客戶端的變量就用于不會被初始化了; 這種情況下我們就可以用process.nextTick()把上面的asyncFake改成異步執(zhí)行的;
function asyncReal(data, callback){ process.nextTick(function(){ callback(data === 'foo') }) }
用在事件觸發(fā)過程中
EventEmitter 有兩個比較核心的方法,on和Emit。node自帶的發(fā)布/訂閱模式;
var EventEmitter = require('events').EventEmmiter; function StreamLibrary(resourceName){ this.emit('start') } StreamLibrary.prototype.__proto__ = EventEmitter.prototype; // inherit from EventEmitter
var stream = new StreamLibrary('fooResouce'); stream.on('start', function(){ console.log('Reading has started') })
以上代碼在new StreamLibrary的時候,已經(jīng)觸發(fā)了emit,此時 還沒有訂閱,console.log不會執(zhí)行 解決方案如下:用異步方法包裝
function StreamLibrary(resource){ var self = this; // 保證訂閱在發(fā)布之前 process.nextTick(function(){ self.emit('start'); }) // read from the file,and for every chunck read.do; this.emit('data', chunkRead) }
發(fā)布訂閱模式
const EventEmitter = require('events').EventEmitter; class App extends EventEmmiter{ } let app = new App(); app.on('start',() =>{ // 訂閱 console.log('start'); }) app.emit('start') // emit 觸發(fā),emit是個同步的方法 console.log(111); // 如果需要emit是異步的,可以通過三種異步方法去包裝 // start 111
看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進一步的了解或閱讀更多相關(guān)文章,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對創(chuàng)新互聯(lián)的支持。