Q:好了,我们继续聊Node.js。记得上次我提到了“非阻塞”和“事件驱动”,这引起了我的好奇,但又给这两个有点高端的词泼了一盆冷水。A:别着急,我们来看一个简单的场景:你应该用人人网查过朋友的消息吧?有一种简单的方法可以实现这样的功能,那就是在用户和服务器之间保持一个长轮询。但又不同于普通的Ajax。服务器不会立即返回信息,它会先hold住,等信息返回后才会返回信息(比如你的朋友发了一个新状态)。从传统服务器(如Apache)的角度来看,每次有新用户连接到您的网站时,您的服务器都必须打开一个新连接。每个连接都需要占用一个线程,而这些线程大部分是空闲的。(比如等你的朋友发状态,查数据库等),虽然空闲,但是还是占内存的。也就是说,如果用户数量达到一定规模,服务器的内存就会耗尽而瘫痪。解决办法很多,比如使用线程池,但是还是阻塞。如果线程池中的所有线程都阻塞了(网速慢,临时被恶意利用)那么下一个请求就会排队。Node.js是不同的。它使用“非阻塞”和“事件驱动”模型。你可以把它想象成一个事件循环,它会一直运行。一个新的请求来了,EventLoop接收到这个请求,然后交给其他线程,比如查询数据库,然后响应一个回调,然后接收其他请求,而不是等待数据库结果的返回。如果数据库有返回结果,服务器会返回给客户端,循环往复。这是事件驱动的:服务器只有在有事情发生的时候才会有相应的处理(或者接受请求,或者一些回调)。Q:从这个角度来看,Node.js的非阻塞和事件驱动就是基于这个EventLoop?A:是的,简单来说,Node.js的EventLoop是基于libuv的,而浏览器的EventLoop是在html5规范中定义的,具体实现留给浏览器厂商。问:有趣的是,有两种事件循环。A:相比较而言,它们有些类似:在浏览器中都比较简单。值得注意的是,每执行完一个task,就会执行当前microtask队列中的所有task:Node.js稍微复杂一点,每个EachEventLoop需要经过六个阶段。每个阶段之后,nextTick,microtasks(resolvedpromise等)会被执行:┌──────────────────────────────────────────┐┌──>│计时器│<────setTimeout/setInterval回调│└────────────────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────成为────────────────────┐│││nextTick队列│││<────────────────────────────┐┐││nextTick队列││┌─────────────┴──────────────────────────────────────────────────────────────────────────────────────┘││I/O回调││└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐│││nextTick队列│││<──────────────────│││││microTask队列││┌────────────┴──────────────┐└─────────────────────────────────────────────────────────────────────────┘│空闲,准备│<────仅限内部使用│└────────────┬────────────┘││┌────────────────────────┐│││nextTick队列│││<────────────────│││││microTask队列│││└────────────────────────────┘││┌────────────────────────┐│┌──────────┴────────────┐│传入:│││投票│<────┤连接数,││└──────────┬──────────────┘│数据等│││└──────────────────────────┘││┌──────────────────────────┐│││nextTick队列│││<────────────────│││││microTask队列│││└────────────────────────┘│┌──────────┴─────────────┐││检查│<────setImmediatecallback│└──────────┬────────────┘┌─────────────────────────┐│││nextTick队列│││<──────────────│││││microTask队列││┌──────────┴────────────┐└──────────────────────────┘││关闭回调│<────例如:socket.on("close",func)│└────────────┬──────────────┘┌──────────────────────────┐│││nextTick队列│││<────────────────││└────────────┴│微任务队列│└──────────────────────────┘来一段简单的代码,猜猜浏览器(Chrome)和Node.js分别输出什么:console.log('start');setTimeout(()=>{console.log('timer1');Promise.resolve().then(()=>{console.log('promise1');});},0);setTimeout(()=>{控制台e.log('timer2');Promise.resolve().then(()=>{console.log('promise2');});},0);console.log('结束');Q:在浏览器(Chrome)中,必须输出start、end、time1、promise1、time2、promise2。至于Node.js,我猜是一样的吧?A:我们先验证一下:在浏览器中:startendtimer1promise1timer2promise2在Node.js中:startendtimer1timer2promise1promise2好像和想象中的不一样,不用担心,看动画就明白了:在浏览器中:Node.js中:Q:原来是这样的,如果在每个setTimeout回调中都加上process.nextTick,就会在Promise.then之前执行?A:是的,记住我上面说的。在每个阶段之后,将执行nextTick队列和micktasks队列。nextTick队列的优先级高于micktasks队列的优先级。问:我明白了。对了,我记得你提到过libuv,它是什么?不是说Node.js用的是v8吗,和v8有什么关系?A:...未完待续...其他学习Node.js的Q&A方法(1)参考https://blog.csdn.net/wtopps/...Node.js是做什么用的?-厂长的回答Promises,Next-TicksandImmediates—NodeJSEventLoopPart3fasterasynchronousfunctionsandPromise
