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

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

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


1. 今日主食 🍞


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


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


微信截图_20220512183003.png


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


微信截图_20220512183012.png


  • 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(),而这几个有什么不同呢?更多请看文档 express Response


  • res.end()


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


  • res.send(body)


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


微信截图_20220512183042.png


  • res.render


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


微信截图_20220512183054.png


首先是配置说明


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


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


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


关于 res.render结合模版引擎更多用法,推荐阅读: Express:模板引擎深入研究


  • 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服务集群。


微信截图_20220512183122.png

微信截图_20220512183135.png


通过上述代码我们就创建了一个支持多进程和负载均衡的服务,运行结果如下👇


微信截图_20220512183148.png


啊呆👦同学:那为什么多个进程可以监听同一个端口呢?


上面运行的Demo中,成功的开启了 1 个 Master 进程及8个 Worker 进程,因为监听的只有3000一个端口,按道理的话,一个端口被多个进程监听是会报端口冲突的,但是这时候却没有报错,奇了怪了?,让我们看下一下端口查看详情👇


微信截图_20220512183208.png


我去~原来3000端口并不是被所有进程监听,而是仅仅监听 Master 进程(pid为'32101'), 我们再来看看Master 进程和Worker的关系


微信截图_20220512183218.png


Master 通过 cluster.fork() 这个方法创建的,本质上还是使用的 child_process.fork() 这个方法,关于 cluster、child_process、Process等的关系可以看这篇 Node.js cluster 踩坑小结


啊宽👦同学:除了上面的方式实现多进程及负载均衡还有其他方式吗?


可以使用PM2工具来实现, pm2内部包含了所有上述的处理逻辑,我们可以不用对原来的代码进行修改,只要再启动的时候使用pm2管理即可,运行pm2 start test.js -i 2


微信截图_20220512183233.png


  • pm2 start test.js -i 2


意思是cluster mode 模式启动2个app.js的应用实例,这2个应用程序会自动进行负载均衡,- i后面的数字表示要启动的工作线程的数量。如果给定的数字为0,PM2则会根据你CPU核心的数量来生成对应的工作线程


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


更多关于pm2 的使用可以看之前树酱写的:前端运维部署那些事


1.4 node是怎样支持https?


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


微信截图_20220512183252.png


微信截图_20220512183307.png


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


答案:可以通过在路由设置里面加了header的设置即可


微信截图_20220512183317.png


啊乐👧同学:这里使用到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 官方文档


微信截图_20220512183329.png


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


答案是:通过fork,原理是子程序用process.on来监听父程序的消息,用 process.send给子程序发消息,父程序里用child.on,child.send进行交互,来实现父进程和子进程互相发送消息


微信截图_20220512183341.png


微信截图_20220512183408.png


child_process模块


提供了衍生子进程的功能,包括前几节提到的cluster底层实现还是child_process


该模块主要包括以下几个异步进程函数


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


未完待续...



相关实践学习
部署高可用架构
本场景主要介绍如何使用云服务器ECS、负载均衡SLB、云数据库RDS和数据传输服务产品来部署多可用区高可用架构。
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
4天前
|
JavaScript NoSQL 中间件
不容错过的 Node 库都有那些?
【4月更文挑战第7天】 探索Node.js生态:Express用于构建Web服务器,Mongoose简化MongoDB操作,Socket.IO实现实时通信。Express提供简洁API和路由功能,Mongoose支持数据验证,Socket.IO确保跨平台实时连接。示例代码展示如何使用这些库,助你提升开发效率。
21 0
|
2天前
|
存储 JavaScript 前端开发
node面试知识
node面试知识
6 0
|
9月前
|
前端开发
前端学习笔记202306学习笔记第四十三天-学习node的必要性1
前端学习笔记202306学习笔记第四十三天-学习node的必要性1
38 0
|
9月前
|
前端开发
前端学习笔记202306学习笔记第四十三天-学习node的必要性2
前端学习笔记202306学习笔记第四十三天-学习node的必要性2
47 0
|
10月前
|
缓存 JavaScript API
Node冷门知识点——require('node:path')
今天在看Vite的源码时候,发现有个用法很神奇
131 0
|
存储 JavaScript 前端开发
node笔记记录52两道面试题之面试题1之2
node笔记记录52两道面试题之面试题1之2
41 0
node笔记记录52两道面试题之面试题1之2
node笔记记录52两道面试题之面试题1之1
node笔记记录52两道面试题之面试题1之1
43 0
node笔记记录52两道面试题之面试题1之1
node43-服务器基础概念
node43-服务器基础概念
50 0
node43-服务器基础概念
Node gRPC 初印象 && 跑起来 (1)
Node gRPC 初印象 && 跑起来 (1)
133 0