文章目录
- node模块
- Node基础
- node有哪些特征,与其他服务器端对比
- 如何判断当前脚本运行在浏览器还是node环境中
- node怎么跟MongoDB建立连接
- V8的垃圾回收机制
- 如何查看V8的内存使用情况
- V8的内存分代和回收算法
- 哪些情况会造成V8无法立即回收内存
- webSocket
- 进程通信
- 请简述一下node的多进程架构
- 创建子进程的方法有哪些,简单说一下它们的区别
- 你知道spawn在创建子进程的时候,第三个参数有一个stdio选项吗,这个选项的作用是什么,默认的值是什么。
- 实现一个node子进程被杀死,然后自动重启代码的思路
- 以上基础上,实现限量重启,比如我最多让其在1分钟内重启5次,超过了就报警给运维
- 如何实现进程间的状态共享,或者数据共享
- 中间件
- 如果使用过koa、egg这两个Node框架,请简述其中的中间件原理
- koa中间件实现源码
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 &#61; 0; i < cpus.length; i&#43;&#43;){fork(&#39;./worker.js&#39;);
}
在linux中&#xff0c;我们通过ps aux | grep worker.js查看进程
创建子进程的方法有哪些&#xff0c;简单说一下它们的区别
- spawn()&#xff1a; 启动一个子进程来执行命令
- exec(): 启动一个子进程来执行命令&#xff0c;与spawn()不同的是其接口不同&#xff0c;它有一个回调函数获知子进程的状况
- execFlie(): 启动一个子进程来执行可执行文件
- fork(): 与spawn()类似&#xff0c;不同电在于它创建Node子进程需要执行js文件
spawn()与exec()、execFile()不同的是&#xff0c;后两者创建时可以指定timeout属性设置超时时间&#xff0c;一旦创建的进程超过设定的时间就会被杀死
exec()与execFile()不同的是&#xff0c;exec()适合执行已有命令&#xff0c;execFile()适合执行文件。
你知道spawn在创建子进程的时候&#xff0c;第三个参数有一个stdio选项吗&#xff0c;这个选项的作用是什么&#xff0c;默认的值是什么。
- 选项用于配置在父进程和子进程之间建立的管道。
- 默认情况下&#xff0c;子进程的 stdin、 stdout 和 stderr 会被重定向到 ChildProcess 对象上相应的 subprocess.stdin、subprocess.stdout 和 subprocess.stderr 流。
- 这相当于将 options.stdio 设置为 [‘pipe’, ‘pipe’, ‘pipe’]。
实现一个node子进程被杀死&#xff0c;然后自动重启代码的思路
在创建子进程的时候就让子进程监听exit事件&#xff0c;如果被杀死就重新fork一下
var createWorker &#61; function(){var worker &#61; fork(__dirname &#43; &#39;worker.js&#39;)worker.on(&#39;exit&#39;, function(){console.log(&#39;Worker&#39; &#43; worker.pid &#43; &#39;exited&#39;);createWorker()})
}
以上基础上&#xff0c;实现限量重启&#xff0c;比如我最多让其在1分钟内重启5次&#xff0c;超过了就报警给运维
- 思路大概是在创建worker的时候&#xff0c;就判断创建的这个worker是否在1分钟内重启次数超过5次
- 所以每一次创建worker的时候都要记录这个worker 创建时间&#xff0c;放入一个数组队列里面&#xff0c;每次创建worker都去取队列里前5条记录
- 如果这5条记录的时间间隔小于1分钟&#xff0c;就说明到了报警的时候了
如何实现进程间的状态共享&#xff0c;或者数据共享
Kafka这类消息队列工具
中间件
如果使用过koa、egg这两个Node框架&#xff0c;请简述其中的中间件原理
- 洋葱圈模型&#xff0c;就是说中间件执行就像洋葱一样&#xff0c;最早use的中间件&#xff0c;就放在最外层。处理顺序从左到右&#xff0c;左边接收一个request&#xff0c;右边输出返回response
- 一般的中间件都会执行两次&#xff0c;调用next之前为第一次&#xff0c;调用next时把控制传递给下游的下一个中间件。当下游不再有中间件或者没有执行next函数时&#xff0c;就将依次恢复上游中间件的行为&#xff0c;让上游中间件执行next之后的代码
const Koa &#61; require(&#39;koa&#39;)
const app &#61; new Koa()
app.use((ctx, next) &#61;> {console.log(1)next()console.log(3)
})
app.use((ctx) &#61;> {console.log(2)
})
app.listen(3001)
koa中间件实现源码
const delay &#61; async () &#61;> {return new Promise((resolve, reject) &#61;> {setTimeout(() &#61;> {resolve();}, 2000);});
}
const fn1 &#61; async (ctx, next) &#61;> {console.log(1);await next();console.log(2);
}
const fn2 &#61; async (ctx, next) &#61;> {console.log(3);await delay();await next();console.log(4);
}
const fn3 &#61; async (ctx, next) &#61;> {console.log(5);
}const middlewares &#61; [fn1, fn2, fn3];
const compose &#61; (middlewares, ctx) &#61;> {const dispatch &#61; (i) &#61;> {let fn &#61; middlewares[i];if(!fn){ return Promise.resolve() }return Promise.resolve(fn(ctx, () &#61;> {return dispatch(i&#43;1);}));}return dispatch(0);
}compose(middlewares, 1);