1.nodejs背景先说说nodejs最常提到的关键词,“单线程”、“非阻塞异步IO”、“事件循环”。接下来我们主要通过这几个关键词来总结一下nodejs的内部原理,以及一些衍生的问题。2、nodejs是单线程的吗?如果nodejs是单线程语言,你可以想象当一个单实例的nodejs服务器同时接受100个用户请求时,第100个用户的请求要等到前面99个用户都处理完了才能处理。前端训练如果每个用户的请求需要0.3秒,第100个用户需要等待30秒,这显然不符合我们的实际情况,所以nodejs不是简单的单线程。那么为什么nodejs是单线程语言呢?但是由于nodejs中javascript代码的执行是单线程的,所以这句话怎么理解,看下面的代码。console.log('javascriptstart');setTimeout(()=>{console.log('javascriptsetTimeout');},2000);constnow=Date.now();while(Date.now(){console.log('requestid:%d,time:',num++,Date.now());fs.readFile('./test.txt',()=>{res.end('response');});}).listen(9007,()=>{console.log('serverstart,127.0.0.1:9007');});//req.jsconsthttp=require('http');for(leti=0;i<100;i++){http.get('http://127.0.0.1:9007',(res)=>{res.on("data",(data)=>{console.log('响应时间:',Date.now())//console.log('data',data.toString())})}).on('error',(err)=>{console.log('error',err);})}nodehttp.js//启动服务器nodereq.js//发起100个请求,可以看出100个请求都是在请求返回前很短的时间内处理完的,返回的都是在请求之后,并不是requests按照receive的顺序等待每个IO处理完,然后依次返回。4.事件循环说到事件循环,在上面的请求中,在很短的时间内处理了100个请求,然后分别对请求进行了响应。大家可以想一想,javascript已经执行到第100个请求了。第一个请求被应答了,第一个请求的栈信息没有丢失,说明记录了第一个请求的请求栈信息,这个过程就是注册IO事件。从上面注册完事件后,事件循环被激活,web前端训练开始实际执行上面代码中fs.readFile的文件读取IO。这时候IO的执行和javascript代码的执行没有任何关系。nodejs底层libuv提供的线程池接收文件IO执行工作。线程池默认大小为4,启动时可以通过环境变量process.env.UV_THREADPOOL_SIZE进行调整,但最大不能超过1024,有兴趣可以查看线程池源码;从上面可以看出,nodejs其实是多进程并行工作的,只是使用了事件循环来做密封处理。再来说说事件循环。在上面的例子中,当fs.readFile读取一个文件时,它是如何知道读取操作完成的呢?大家可以想一想,读操作是由线程池控制的。在线程执行之前,在注册事件的内存中初始化一个状态为“正在执行”,事件循环也已经启动,开始轮询等待执行结果,IO线程执行完成后,通知底层异步IO接口(epoll_wait/IOCP)到初始注册的任务队列内存改变状态,事件循环轮询直到状态变为“完成”,这意味着这时IO事件注册时注入的回调函数获得执行权,javascript线程开始工作,整个异步过程完成。您可以看到在事件循环中必须经过哪些步骤,如何将其称为事件循环。可以看看英文原版的解释,eventloopexplanation翻译:Stageoverviewtimers:这个阶段执行setTimeout()和setInterval()中过期的回调函数I/Ocallbacks:执行除setTimeout()之外的所有函数,setInterval(),close事件,setImmediate的其他回调函数空闲,prepare:只在内部使用poll:获取新的I/O事件,在合适的条件下nodejs会在这个阶段阻塞check:这里调用了setImmediate的回调函数closecallbacks:像Socket.on("close",func)是一种执行关闭事件的回调。以上内容难免有错误或误解。如果有什么问题,欢迎大家留言指正,以免误导大家。如果对你有帮助,别忘了分享给你的朋友哦!也可以关注作者,查看历史文章,关注最新动态,助你早日成为全栈工程师!