当前位置: 首页 > 后端技术 > Node.js

Node异步与非阻塞漫谈

时间:2023-04-03 16:24:25 Node.js

简介node作为服务器的优势在于适合处理高并发请求。对于网站后台的I/O密集型后台尤其有利。核心是node是一个异步非阻塞的server。阻塞模型。本文不讨论异步、同步、阻塞、非阻塞的概念。Node的单线程模型js作为一种单线程语言,有自己的一套运行机制。同步任务在主线程上运行。所有异步任务都会在另一个队列中等待执行。一旦同步任务被执行,异步队列就会被执行。Task,此时,可以认为将第一个异步队列中的任务移到主线程中。一旦异步操作再次产生,就会继续加入到异步队列中,如此循环下去。这就是为什么promises,setTimeout,setInterval,process.nextTick,setImmediate,ajaxrequests,看似在代码的上半部分却没有按顺序执行的原因。看一下node的eventloop机制,也就是node的异步架构。主要区别在于LIBUV是用来将队列中的任务作为下一个循环要执行的工作,形成一个事件循环。观察者模式的体现个人一直认为js的异步回调是观察者模式的体现,订阅/发布,网上有三种观察者。提到的process.nextTick就属于这类I/O观察者:顾名思义,就是I/O相关的观察者,即I/O的回调事件,比如网络,文件,数据库I/O等检查观察者:顾名思义,就是需要检查的观察者。后面会提到的setTimeout/setInterval就属于这种优先级。一类观察者是定时器观察者,setImmediate()是检查观察者。至于原因,我会在后面解释。下面是我对setTimeout()、setImmediate()和process.nextTick()的比较。首先,所有的讨论都是基于node上面的,三个函数只是比较分析了node中的情况,取自node文档setTimeout()callback定时器到时调用的函数。delay调用回调前等待的毫秒数。在delay毫秒后安排一次性回调的执行。返回与clearTimeout()一起使用的超时。回调可能不会在精确的延迟毫秒内被调用。Node.js不保证回调触发的确切时间,也不保证它们的顺序。回调将在尽可能接近指定时间时调用即兴表演。这里澄清两点。一是settimeout的实际执行时间必须晚于设置的时间。做一个精确的计时器有悖于他的设计初衷。还有一点就是他的函数回调是被timer观察到的setImmediate()callback在本轮Node.js事件循环结束时调用的函数...args调用回调时传递的可选参数。安排回调的“立即”执行在I/O事件回调之后。返回一个与clearImmediate()一起使用的Immediate。当多次调用setImmediate()时,回调函数将按创建顺序排队等待执行。每次事件循环迭代都会处理整个回调队列。如果立即计时器从正在执行的回调中排队,则该计时器将不会被触发,直到下一次事件循环迭代。核心,回调会被立刻放于eventLoop的末尾process.nextTick()callback...args调用回调时要传递的其他参数他process.nextTick()方法将回调添加到“下一个报价队列”。一旦事件循环的当前回合运行完成,所有回调currently在下一个滴答队列中将被调用。这不是setTimeout(fn,0)的简单别名。它更有效率。它在事件的后续滴答中触发任何其他I/O事件(包括计时器)之前运行在loop.documentation中提到process.nextTick()不是setTimeout(fn,0),它更高效,并且执行顺序必须与下一次所有事件循环的前行进行比较。node文档里面有比较详细的比较,链接比较了这三个函数,先说process.nextTick(),文档说process.nextTick()在技术上不是事件循环的一部分,现在是明确process.nextTick()不在eventloop中,他的callback的执行是在eventwaitingqueue之外,算是最高优先级的跳队者,所以毫无疑问是最高优先级执行打回来。实际使用是有一些回调必须以最高优先级执行,比如网络服务器端,端口的监听要早于其他事件的回调。setImmediate()vssetTimeout()这可能是网上最不一致的地方了。据说谁先执行谁就拥有一切。先测试下面的代码setTimeout(()=>{console.log('timeout');},0);setImmediate(()=>{console.log('immediate');});结果真的是随机的,这么不精确?其实官方对此是有解释的。计时器的执行顺序将根据调用它们的上下文而有所不同。如果两者都从主模块中调用,那么时间将受进程性能的限制(这可能会受到机器上运行的其他应用程序的影响)。但是,如果您在I/O周期内移动这两个调用,theimmediatecallbackisalwaysfirstexecuted:这教会了我真理是有极限的,所谓普世真理是玄学。所以setImmediate()vssetTimeout()不能简单的说谁更快,要先讨论用在什么地方。上面提到setTimeout(fn,0)效率不高。至于为什么,暂时参考国内一般的说法,这个函数的事件控制是维护在红黑树上的,所以每次都要logn回调,找超时时间其他两个函数的复杂度好像是1.总结综上所述,我倾向于说有四个观察者。至于setImmediate()vssetTimeout()vsprocess.nextTick(),process.nextTick()最快速和独特的应用场景。另外两个的调用时间需要判断是否都在主线程中执行。setTimeout(fn,0)效率低下。tip:Node官方推荐使用setimmediate(),因为至少应用的作用域可以到达浏览器。