面试官问你关于node的那些事(进阶篇)

    技术2022-07-10  231

    前沿:续上次面试官问你关于node的那些事基础篇发出,童鞋反馈说“怎么那么基础啊,这也太水了吧” 这里统一做回复,不基础咋叫“基础篇”呢,因为本人也不是什么大神,渣渣一枚,只是通过自己的角度,希望能帮助大家更好地去学习,于是就有了进阶篇的梳理计划,今天我们继续跟你聊聊关于node后续的那些事

    今日主食 🍞

    1.1 注册路由时 app.get、app.use、app.all 的区别是什么?

    上一章基础篇提及到如何使用express搭建一个简单的服务端,基础架子完成搭建好,就需要定义接口路由和中间件,这时候我们就需要在入口文件app.js中定义app.get、app.use及app.all等方法,而这三者之前又有什么区别?我们用例子来说明

    当我们请求/user路由时,会依次输出树酱🌲来了和Hello World,接着浏览器端显示执行完毕,同理访问/user/tree则只会输出 树酱🌲来了,为啥呢? app.use(path,callback)

    app.use是express用来调用中间件的方法。中间件通常不处理请求和响应,一般只处理输入数据,并将其交给队列中的下一个处理程序,比如下面这个例子app.use(’/user’),那么只要路径以 /user 开始即可匹配,如 /user/tree 就可以匹配

    app.all()

    app.all 是路由中指代所有的请求方式,用作路由处理,匹配完整路径,在app.use之后 可以理解为包含了app.get、app.post等的定义,比如app.all(’/user/tree’),能同时覆盖:get(’/user/tree’) 、 post(’/user/tree’)、 put(’/user/tree’) ,不过相对于app.use()的前缀匹配,它则是匹配具体的路由 总结:一句话概括:all完整匹配,use只匹配前缀

    1.2 express response有哪些常用方法?

    express response对象是对Node.js原生对象ServerResponse的扩展,express response常见的有:res.end()、res.send()、res.render()、res.redirect(),而这几个有什么不同呢?

    res.end()

    结束response - 如果服务端没有数据回传给客户端则可以直接用res.end返回,以此来结束响应过程

    res.send(body)

    如果服务端有数据可以使用res.send,可以忽略res.end,body参数可以是一个Buffer对象,一个String对象或一个Array

    res.render

    res.render用来渲染模板文件,也可以结合模版引擎来使用,下面看个简单的demo (express+ejs模版引擎) 首先是配置说明

    app.set('views', path.join(__dirname, 'views')); // views:模版文件存放的位置,默认是在项目根目录下 app.set('view engine', 'ejs'); // view engine:使用什么模版引擎

    其次是根据使用的模版引擎语法编写模版,最后通过res.render(view,locals, callback)导出,具体使用参数

    view:模板的路径 locals:渲染模板时传进去的本地变量 callback:如果定义了回调函数,则当渲染工作完成时才被调用,返回渲染好的字符串(正确)或者错误信息 ❌

    res.redirect

    重定义到path所指定的URL,同时也可以重定向时定义好HTTP状态码(默认为302)

    res.redirect('http://baidu.com'); res.redirect(301, 'http://baidu.com');

    1.3 node如何利用多核CPU以及创建集群?

    众所周知,nodejs是基于chrome浏览器的V8引擎构建的,一个nodejs进程只能使用一个CPU(一个CPU运行一个node实例),举个例子:我们现在有一台8核的服务器,那么如果不利用多核CPU,是很一种浪费资源的行为,这个时候可以通过启动多个进程来利用多核CPU Node.js给我们提供了cluster模块,用于nodejs多核处理,同时可以通过它来搭建一个用于负载均衡的node服务集群。

    通过上述代码我们就创建了一个支持多进程和负载均衡的服务,运行结果如下👇 啊呆👦同学:那为什么多个进程可以监听同一个端口呢? 上面运行的Demo中,成功的开启了 1 个 Master 进程及8个 Worker 进程,因为监听的只有3000一个端口,按道理的话,一个端口被多个进程监听是会报端口冲突的,但是这时候却没有报错,奇了怪了?,让我们看下一下端口查看详情👇 我去~原来3000端口并不是被所有进程监听,而是仅仅监听 Master 进程(pid为’32101’), 我们再来看看Master 进程和Worker的关系 Master 通过 cluster.fork() 这个方法创建的,本质上还是使用的 child_process.fork() 这个方法

    啊宽👦同学:除了上面的方式实现多进程及负载均衡还有其他方式吗? 可以使用PM2工具来实现, pm2内部包含了所有上述的处理逻辑,我们可以不用对原来的代码进行修改,只要再启动的时候使用pm2管理即可,运行pm2 start test.js -i 2 pm2 start test.js -i 2 意思是cluster mode 模式启动2个app.js的应用实例,这2个应用程序会自动进行负载均衡,- i后面的数字表示要启动的工作线程的数量。如果给定的数字为0,PM2则会根据你CPU核心的数量来生成对应的工作线程

    拓展:我们可以通过借助cluster模块来实现多进程分页爬虫,Node多进程架构可以充分利用 cpu 资源,我们在一些耗时的操作上,可以尝试这种方式来解决。

    1.4 node是怎样支持https?

    https实现,离不开证书,通过openssl生成公钥私钥(不做详细介绍),然后基于 express的 https模块 实现,设置options配置, options有两个选项,一个是证书本体,一个是密码

    1.5 node和客户端怎么解决跨域的问题?

    答案:可以通过在路由设置里面加了header的设置即可 啊乐👧同学:这里使用到app.use(’’)是什么意思呀? 后面添加 可以实现全匹配, app.all(’*’,(req,res,next)=>{}) 效果相当于app.use((req,res,next)=>{}), 这也是app.all的一个比较常见的应用,就是用来处理跨域请求

    1.6 node应用内存泄漏咋搞?

    内存泄漏(Memory Leak)指由于错误造成程序未能释放已经不再使用的内存的情况。如果内存持续占用过高,会影响服务器响应,情况严重直接能让程序奔溃,那么怎么尽量避免这种情况出现,或者出现了怎么排查呢? 导致内存泄漏有主要以下几点:

    全局变量没有手动销毁,因为全局变量不会被回收闭包:闭包中的变量被全局对象引用,则闭包中的局部变量不能释放监听事件添加后,没有移除,会导致内存泄漏 这也同时涉及到垃圾回收(GC),nodejs是执行javascript的V8引擎,也就是说nodejs的GC就是说V8引擎的GC,而基于GC的原理,内存泄漏就是应该被回收的内存,换句话说就是本应该被标记为可达到对象却没有被正常回收

    啊开👦同学:那么如果一旦出现内存泄漏怎么检测? 通过内存快照,可以使用node-heapdump 官方文档获得内存快照进行对比,查找内存溢出 可视化内存泄漏检查工具 Easy-Monitor 官方文档

    1.7 两个node程序之间怎样交互?

    答案是:通过fork,原理是子程序用process.on来监听父程序的消息,用 process.send给子程序发消息,父程序里用child.on,child.send进行交互,来实现父进程和子进程互相发送消息 child_process模块 提供了衍生子进程的功能,包括前几节提到的cluster底层实现还是child_process 该模块主要包括以下几个异步进程函数

    fork:就是上面代码中实现父进程和子进程互相发送消息的方法,通过fork可以在父进程和子进程之间开放一个IPC通道,使得不同的node进程间可以进行消息通信。exec: 衍生一个 shell 并在该 shell 中运行命令,当完成时则将stdout 和 stderr 传给回调函数,exec的第一个参数,跟shell命令完全相似,场景用来执行命令较多 关于exec应用场景可以看树酱之前写的:从0到1开发简单脚手架spawn

    未完待续点个关注呗…

    原文链接:https://juejin.im/post/5ef57aca6fb9a07e5f516814

    Processed: 0.027, SQL: 9