本文转载自微信公众号《Nodejs技术栈》,作者吴跃军。转载本文请联系Nodejs技术栈公众号。Node.js小知识记录一些工作中遇到的问题或者在“Nodejs技术栈”交流群。有时候一个小问题可以扩展出很多新的知识点。解决问题和总结的过程本身也是一个成长的过程,在这里和大家分享一下成长。使用JavaScript/Node.js的开发者如果遇到需要延迟的任务,可能会有疑问🤔?为什么Java中没有像Thread.sleep()那样实现线程休眠的方法?在Node.js中实现一个sleep()函数。一:坏的“循环空转”下面的一段代码是坏的。Node.js是单进程单线程启动的,所有业务代码都在主线程上工作,会造成CPU持续占用,阻塞主线程,也是CPU资源的浪费,远非如此真正的线程休眠。conststart=newDate();while(newDate()-start<2000){}运行后,如上图,CPU会暴涨,同时事件循环调度会被破坏,导致其他任务无法执行。2:Timer+Promise通过定时器延时执行函数setTimeout+Promise链依赖实现实现sleep,本质是新建一个Promise对象,然后在定时器延时时间到后执行resolve函数,这里Node.js执行线程不休眠,事件循环和V8正常运行。不过这也是目前比较普遍的解决办法,因为不能让主线程阻塞,否则程序就没法继续工作了。constsleep=ms=>newPromise(resolve=>setTimeout(resolve,ms));在Node.js中,也可以使用util模块提供的promisify方法实现,快捷方式。const{promisify}=require('util');constsleep=promisify(setTimeout);因为是基于timer和Promise,自然是异步的,所以使用的时候要注意,如下图://asyncawaitmethodasyncfunctiontest(){console.log(1);awaitsleep(3000);console.log(2);}//Promise链调用方法asyncfunctiontest(){console.log(1);sleep(3000).then(()=>{console.log(2);});}第三:零CPU开销,真正的事件循环防止睡眠实现ECMA262草案提供了Atomics.waitAPI来实现线程睡眠,它会真正阻??塞事件循环,阻塞线程直到超时。Atomics.wait(Int32Array,index,value[,timeout])方法将验证给定的Int32Array数组位置是否仍然包含它的值,它会等待唤醒或直到睡眠状态超时,并返回一个字符串指示是否超时或未唤醒。同样的,因为我们的业务是工作在主线程上的,所以避免在主线程中使用,根据实际需要在Node.js工作线程中使用。/***真正阻塞事件循环,阻塞线程直到超时,不要在主线程constvalid上使用*@param{Number}msdelay*@returns{String}ok|not-equal|timed-out*/functionsleep(ms){=ms>0&&ms
