挑战⼀轮⼤⼚后的⾯试总结(含六个⽅向)-nodejs篇
在去年底开始换⼯作,直到现在算是告了⼀个段落,断断续续的也⾯试了不少公司,现在回想起来,那段时间经历了被⾯试官⼿撕,被笔试题狂怼,悲伤的时候差点留下没技术的泪⽔。
这篇⽂章我打算把我⼯作遇到的各种⾯试题(每次⾯试完我都会总结)和我⾃⼰复习遇到⽐较有意思的题⽬,做⼀份汇总,年后是跳槽⾼峰期,也许能帮到⼀些⼩伙伴。
先说下这些题⽬难度,⼤部分都是基础题,因为这段经历给我的感觉就是,不管你⾯试的是⾼级还是初级,基础的知识⼀定会问到,甚⾄会有⼀定的深度,所以基础还是⾮常重要的。
我将根据类型分为⼏篇⽂章来写:
(已完成) 强烈⼤家看看这篇,⾯试中 js 是⼤头
(已完成)
(已完成)
(已完成)
(已完成)
(已完成)
六篇⽂章都已经更新完啦~
这篇⽂章是对 nodejs 相关的题⽬做总结,欢迎朋友们先收藏在看。
先看看⽬录
Q: 怎么看 nodejs 可⽀持⾼并发
这个问题涉及了好⼏个⽅⾯啊,聊的好,是个很好的加分项。可按照以下步骤给⾯试官解释
1. nodejs 的单线程架构模型
nodejs 其实并不是真正的单线程架构,因为 nodejs 还有I/O线程存在(⽹络I/O、磁盘I/O),这些I/O线程是由更底层的 libuv 处理,这部分线程对于开发者来说是透明的。 JavaScript 代码永远运⾏在V8上,是单线程的。
所以从开发者的⾓度上来看 nodejs 是单线程的。
来张⽹图:
注意看图的右边有个 Event Loop,接下来要讲的重点
单线程架构的优势和劣势:
优势:
单线程就⼀个线程在玩,省去了线程间切换的开销
还有线程同步的问题,线程冲突的问题的也不需要担⼼
劣势:
劣势也很明显,现在起步都是 4 核,单线程没法充分利⽤ cpu 的资源
单线程,⼀旦崩溃,应⽤就挂掉了,⼤家调试脚本也知道⼀旦执⾏过程报错了,本次调试就直接结束了
因为只能利⽤⼀个 cpu ,⼀旦 cpu 被某个计算⼀直占⽤, cpu 得不到释放,后续的请求就会⼀直被挂起,直接⽆响应了
当然这些劣势都已经有成熟的解决⽅案了,使⽤ PM2 管理进程,或者上 K8S 也可以
2. 核⼼:事件循环机制
那你个单线程怎么⽀持⾼并发呢?
核⼼就要在于 js 引擎的事件循环机制(我觉得这个开场还挺不错)
浏览器和 nodejs 的事件循环是稍有区别的,先给⾯试官简单说下事件循环的核⼼,执⾏栈、宏队列和微队列,具体的介绍可以看我以前写的⼀篇总结
然后重点说 nodejs 事件循环的差异点,因不想把两个问题混在⼀起,所以独⽴成⼀个问题,具体讲解⼤家稍微往下翻看下⼀个问题的解答。
3. 给出个结论 nodejs 是异步⾮阻塞的,所以能扛住⾼并发
来个个栗⼦:
⽐如有个客户端请求A进来,需要读取⽂件,读取⽂件后将内容整合,最后数据返回给客户端。但在读取⽂件的时候另⼀个请求进来了,那处理的流程是怎么样的?
灵魂画⼿,我整了张图,⼤家理解就好
请求A进⼊服务器,线程开始处理该请求
A 请求需要读取⽂件,ok,交给⽂件 IO 处理,但是处理得⽐较慢,需要花 3 秒,这时候 A 请求就挂起(这个词可能不太恰当),等
待通知,⽽等待的实现就是由事件循环机制实现的,
在A请求等待的时候,cpu 是已经被释放的,这时候B请求进来了, cpu 就去处理B请求
两个请求间,并不存在互相竞争的状态。那什么时候会出现请求阻塞呢?涉及到⼤量计算的时候,因为计算是在 js 引擎上执⾏的,执⾏栈⼀直卡着,别的函数就没法执⾏,举个栗⼦,构建⼀个层级⾮常深的⼤对象,反复对这个这个对象
JSON.parse(JSON.stringify(bigObj))
4. 有机会的话可以给⾯试官扩展 同步、异步、阻塞、⾮阻塞 这个⼏个概念
同步和异步关注的是消息通信机制。
同步:在发起⼀个调⽤后,在没有得到结果前,该调⽤不返回,知道调⽤返回,才往下执⾏,也就是说调⽤者等待被调⽤⽅返回结果。
异步:在发起⼀个调⽤后,调⽤就直接返回,不等待结果,继续往下执⾏,⽽执⾏的结果是由被调⽤⽅通过状态、通知等⽅式告知调⽤⽅,典型的异步编程模型⽐如 Node.js
阻塞和⾮阻塞,关注的是在等待结果时,线程的状态。
阻塞:在等待调⽤结果时,线程挂起了,不往下执⾏
⾮阻塞:与上⾯相反,当前线程继续往下执⾏
Q: 介绍下 nodejs 的事件循环
这⾥假设⼤家已经对浏览器的事件循环有了解,看下图:
如上图,事件循环中细分为这六个阶段,依次如下:
1. Timers: 定时器 Interval Timoout 回调事件,将依次执⾏定时器回调函数
2. Pending: ⼀些系统级回调将会在此阶段执⾏
3. Idle,prepare: 此阶段"仅供内部使⽤"
4. Poll: IO回调函数,这个阶段较为重要也复杂些,
5. Check: 执⾏ setImmediate() 的回调
6. Close: 执⾏ socket 的 close 事件回调
开发需要关系的阶段
与我们开发相关的三个阶段分别是 Timers Poll Check
Timers :执⾏定时器的回调,但注意,在 node 11 前,连续的⼏个定时器回调会连续的执⾏,⽽不是像浏览器那样,执⾏完⼀个宏任务⽴即执⾏微任务。
Check :这个阶段执⾏ setImmediate() 的回调,这个事件只在 nodejs 中存在。
Poll :上⾯两个阶段的触发,其实是在 poll 阶段触发的,poll 阶段的执⾏顺序是这样的。
1. 先查看 check 阶段是否有事件,有的话执⾏
2. 执⾏完 check 阶段后,检查 poll 阶段的队列是否有事件,若有则执⾏
3. poll 的队列执⾏完成后,执⾏ check 阶段的事件
在 nodejs 中也是有宏任务和微任务的, nodejs 中除了多了 Tick ,宏任务、微任务的分类都是⼀致的。
那么微任务是在什么时候执⾏呢?
在上图,黄⾊的⼏个阶段的旁边挨着个⼩块 microtask,每个阶段执⾏后就⽴即执⾏微任务队列⾥的事件。
下⾯有个栗⼦说明。
微队列的栗⼦
如下代码:
const fs =require('fs');
const ITERATIONS_MAX=3;
let iteration =0;
const timeout =setInterval(()=>{
console.log('START: setInterval','TIMERS PHASE');
if(iteration <ITERATIONS_MAX){
setTimeout(()=>{
console.log('setInterval.setTimeout','TIMERS PHASE');
});
if(err)throw err;
console.log('fs.readdir() callback: Directory contains: '+ files.length +' files','POLL PHASE');
});
setImmediate(()=>{
console.log('setInterval.setImmediate','CHECK PHASE');
});
nodejs工作流引擎开源}else{
console.log('Max interval count exceeded. Goodbye.','TIMERS PHASE');
clearInterval(timeout);
}
iteration++;
console.log('END: setInterval','TIMERS PHASE');
},0);
// 第⼀次执⾏
// START: setInterval TIMERS PHASE
// END: setInterval TIMERS PHASE
// setInterval.setImmediate CHECK PHASE
// setInterval.setTimeout TIMERS PHASE
// 第⼆次执⾏
/
/ START: setInterval TIMERS PHASE
// END: setInterval TIMERS PHASE
// fs.readdir() callback: Directory contains: 9 files POLL PHASE
// fs.readdir() callback: Directory contains: 9 files POLL PHASE
// setInterval.setImmediate CHECK PHASE
// setInterval.setTimeout TIMERS PHASE
// 第三次执⾏
// START: setInterval TIMERS PHASE
// END: setInterval TIMERS PHASE
// setInterval.setImmediate CHECK PHASE
// fs.readdir() callback: Directory contains: 9 files POLL PHASE
/
/ setInterval.setTimeout TIMERS PHASE
关于 Tick ,这个事件的优先级要⾼于其他微队列的事件,所以对于需要⽴即执⾏的回调事件可以通过该⽅法将事件放置到微队列的起始位置。
如下代码:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。