nodejs中如何实现事件循环,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。
process.nextTick()不在event loop的任何阶段执行,而是在各个阶段切换的中间执行;即从一个阶段切换到下个阶段前执行;
三种定义异步事件的方式: 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
在多个事件交叉执行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()
在这种模式下,我们不需要递归的调用compute(),我们只需要在事件循环中使用process.nextTict()定义;compute()在下一个事件点执行即可;在这个过程中,如果有新的http请求进来,事件循环机制会先处理新的请求,然后再调用copute().反之,如果把compute()放在一个递归里调用,那系统一直会阻塞在compute()里,无法处理新的http请求了。
保持回调函数异步执行的原则
当给一个函数定义一个回调函数时,要确保这个回调是异步执行的(定义一个callback,但是又需要在callback里面使用这个变量);
下面示例违反了这一原则:
function asyncFake(data,callback){ // 同步执行 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()变成同步执行的了,回调函数就会立刻被执行,因此回调函数写到客户端的变量就用于不会被初始化了; 这种情况下我们就可以用process.nextTick()把上面的asyncFake改成异步执行的;
function asyncReal(data, callback){ process.nextTick(function(){ callback(data === 'foo') }) }
用在事件触发过程中
EventEmitter 有两个比较核心的方法,on和Emit。node自带的发布/订阅模式;
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的时候,已经触发了emit,此时 还没有订阅,console.log不会执行 解决方案如下:用异步方法包装
function StreamLibrary(resource){ var self = this; // 保证订阅在发布之前 process.nextTick(function(){ self.emit('start'); }) // read from the file,and for every chunck read.do; this.emit('data', chunkRead) }
发布订阅模式
const EventEmitter = require('events').EventEmitter; class App extends EventEmmiter{ } let app = new App(); app.on('start',() =>{ // 订阅 console.log('start'); }) app.emit('start') // emit 触发,emit是个同步的方法 console.log(111); // 如果需要emit是异步的,可以通过三种异步方法去包装 // start 111
看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注亿速云行业资讯频道,感谢您对亿速云的支持。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。