常见面试题集合之--node
2023-09-27 14:27:10 时间
node模块
请介绍一下require的模块加载机制
1、先计算模块路径
2、如果模块在缓存里面,取出缓存
3、加载模块
4、输出模块的exports属性即可
Node基础
node有哪些特征,与其他服务器端对比
特征:单线程、事件驱动、非阻塞I/O
node 无法直接渲染静态页面,提供静态服务
node 没有根目录的概念
node 必须通过路由程序指定文件才能渲染文件
node 比其他服务端性能更好,速度更快
如何判断当前脚本运行在浏览器还是node环境中
通过判断 Global 对象是否为 window ,如果不为window ,当前脚本没有运行在浏览器中
node怎么跟MongoDB建立连接
- 引入mongoose
- 使用mongoose.connect()方法连接到MongoDB数据库
- 监听连接是否成功
- 然后通过node,书写接口,对数据库进行增删改查
V8的垃圾回收机制
如何查看V8的内存使用情况
使用 process.memoryUsage()
,返回如下
{
rss: 4935680,
heapTotal: 1826816,
heapUsed: 650472,
external: 49879
}
V8的内存分代和回收算法
在V8中,主要将内存分为新生代和老生代两代。新生代中的对象存活时间较短的对象,老生代中的对象存活时间较长,或常驻内存的对象。
哪些情况会造成V8无法立即回收内存
闭包和全局变量
webSocket
webSocket与传统的http有什么优势
- 客户端与服务器只需要一个TCP连接,比 http 长轮询使用更少的连接
- webSocket 服务端可以推送数据到客户端
- 更轻量的协议头,减少数据传输量
进程通信
请简述一下node的多进程架构
面对node单线程对多核CPU使用不足的情况,Node提供了child_process模块,来实现进程的复制,node的多进程架构是主从模式,如下所示:
var fork = require('child_process').fork;
var cpus = require('os').cpus();
for(var i = 0; i < cpus.length; i++){
fork('./worker.js');
}
在linux中,我们通过ps aux | grep worker.js查看进程
创建子进程的方法有哪些,简单说一下它们的区别
- spawn(): 启动一个子进程来执行命令
- exec(): 启动一个子进程来执行命令,与spawn()不同的是其接口不同,它有一个回调函数获知子进程的状况
- execFlie(): 启动一个子进程来执行可执行文件
- fork(): 与spawn()类似,不同电在于它创建Node子进程需要执行js文件
spawn()与exec()、execFile()不同的是,后两者创建时可以指定timeout属性设置超时时间,一旦创建的进程超过设定的时间就会被杀死
exec()与execFile()不同的是,exec()适合执行已有命令,execFile()适合执行文件。
你知道spawn在创建子进程的时候,第三个参数有一个stdio选项吗,这个选项的作用是什么,默认的值是什么。
- 选项用于配置在父进程和子进程之间建立的管道。
- 默认情况下,子进程的 stdin、 stdout 和 stderr 会被重定向到 ChildProcess 对象上相应的 subprocess.stdin、subprocess.stdout 和 subprocess.stderr 流。
- 这相当于将 options.stdio 设置为 [‘pipe’, ‘pipe’, ‘pipe’]。
实现一个node子进程被杀死,然后自动重启代码的思路
在创建子进程的时候就让子进程监听exit事件,如果被杀死就重新fork一下
var createWorker = function(){
var worker = fork(__dirname + 'worker.js')
worker.on('exit', function(){
console.log('Worker' + worker.pid + 'exited');
// 如果退出就创建新的worker
createWorker()
})
}
以上基础上,实现限量重启,比如我最多让其在1分钟内重启5次,超过了就报警给运维
- 思路大概是在创建worker的时候,就判断创建的这个worker是否在1分钟内重启次数超过5次
- 所以每一次创建worker的时候都要记录这个worker 创建时间,放入一个数组队列里面,每次创建worker都去取队列里前5条记录
- 如果这5条记录的时间间隔小于1分钟,就说明到了报警的时候了
如何实现进程间的状态共享,或者数据共享
Kafka这类消息队列工具
中间件
如果使用过koa、egg这两个Node框架,请简述其中的中间件原理
- 洋葱圈模型,就是说中间件执行就像洋葱一样,最早use的中间件,就放在最外层。处理顺序从左到右,左边接收一个request,右边输出返回response
- 一般的中间件都会执行两次,调用next之前为第一次,调用next时把控制传递给下游的下一个中间件。当下游不再有中间件或者没有执行next函数时,就将依次恢复上游中间件的行为,让上游中间件执行next之后的代码
const Koa = require('koa')
const app = new Koa()
app.use((ctx, next) => {
console.log(1)
next()
console.log(3)
})
app.use((ctx) => {
console.log(2)
})
app.listen(3001)
// 执行结果是1=>2=>3
koa中间件实现源码
// 注意其中的compose函数,这个函数是实现中间件洋葱模型的关键
// 场景模拟
// 异步 promise 模拟
const delay = async () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 2000);
});
}
// 中间间模拟
const fn1 = async (ctx, next) => {
console.log(1);
await next();
console.log(2);
}
const fn2 = async (ctx, next) => {
console.log(3);
await delay();
await next();
console.log(4);
}
const fn3 = async (ctx, next) => {
console.log(5);
}
const middlewares = [fn1, fn2, fn3];
// compose 实现洋葱模型
const compose = (middlewares, ctx) => {
const dispatch = (i) => {
let fn = middlewares[i];
if(!fn){ return Promise.resolve() }
return Promise.resolve(fn(ctx, () => {
return dispatch(i+1);
}));
}
return dispatch(0);
}
compose(middlewares, 1);
相关文章
- 【Java每日面试题】Iterator迭代器到底是什么?
- 2021年Android开发者常见面试题,深度解析,值得收藏
- 游戏面试题-武器升级
- 100个iOS开发面试题汇总
- 一天十道Java面试题----第二天(HashMap和hashTable的区别--------》sleep、wait、join)
- Android面试题-OkHttp3源码分析
- 自动化测试面试题解析,半小时通透
- leetcode面试题16.24-在无序数组中所有发现和为sum的数对
- 大数据面试题百日更新_Hadoop专题_Yarn专题(Day11)
- 【译】系统设计入门之面试题解答 —— 设计一个网页爬虫
- 前端面试题总结:HTML5,JS,CSS3,兼容性。
- 李洪强iOS经典面试题142-第三方框架及其管理
- 李洪强经典面试题36