专业编程基础技术教程

网站首页 > 基础教程 正文

前端面试小结-NODE篇 进来看看说不定有福利哦

ccvgpt 2024-11-25 10:13:58 基础教程 1 ℃

文末有福利

NodeJS

V8 内存管理模型

node 程序运行中,此进程占用的所有内存称为 常驻内存

前端面试小结-NODE篇 进来看看说不定有福利哦

  1. 代码区:存放即将执行的代码片段
  2. 栈:存放局部变量
  3. 堆:存放对象、闭包上下文
  4. 堆外内存:由 c++分配,不受 V8 管理,也不会被 V8 回收。(Buffer 数据)

V8 垃圾回收 :recycle:

  1. 新生代:将内存平均分为两块,使用空间叫 FROM,闲置空间叫 TO。将存活对象分配到 TO 空间,然后清除 FROM 空间调换 FROM 和 TO 空间,继续内存分配新生代晋升老生代多次存活的对象会晋升至老生代To 空间内存使用率超过 25%
  2. 老生代:标记清除 Mark-Sweep (会产生碎片)标记整理 Mark-Compact (整理连续内存)

事件循环

高并发: 单线程 非阻塞 异步 IO(主线程事件循环机制以及底层线程池的实现)

Event Loop

事件循环原理

  1. node 初始化初始化 node 环境执行输入代码执行 process.nextTick 回调执行 microtasks
  2. 进入 Event Looptimers 阶段检查 timer 队列是否有到期的 timer(setTimeout/setInterval)回调,有的话将到期的回调按 timerId 升序执行。IO callback 阶段检查是否有等待(pending)的 IO 回调,有的话执行idle,prepare 阶段nodejs 内部调用poll 阶段检查是否存在尚未完成的回调,如果存在,分两种情况如果队列不为空(包含到期的定时器和 IO 事件),执行可用回调。如果队列为空,检查是否有 setImmediate 回调,如果有,退出 poll 阶段,进入 check 阶段。如果没有,超时之前 node 阻塞在这里,等待新的事件通知。如果不存在尚未完成的回调,直接退出 poll 阶段check 阶段如果有 setImmediate 回调,执行回调closing callback如果套接字或处理函数突然关闭(例如 socket.destroy()),则'close' 事件将在这个阶段发出。在事件循环的每一个子阶段退出之前,都会执行:检查是否有 process.nextTick,有的话执行执行 microtasks退出当前阶段
  3. 检查是否有活跃的 handlers(定时器,IO 事件句柄)如果有,继续下一轮循环没有,就退出事件循环,退出程序

process.nextTick :vs: setImmediate

process.nextTick 是 Nodejs 的一个定时器,他是在本轮循环执行的,而且是所有异步任务中最快执行的。Node 执行完所有同步任务,就会去执行 process.nextTick 任务队列。

process.nextTick 并不属于 Event Loop 中的某一阶段,而在 Event loop 的每一个阶段结束之前,直接执行 nextTickQueue 中插入的 tick,并且直到整个 Queue 处理完。

setImmediate 是在当前任务队列的尾部添加事件,也就是说,它指定的事件总在下一次 Eventloop 执行。

递归调用的 process.nextTick 会导致 IO 饥饿,推荐 setImmediate。

示例:

进程 Process

  1. 查看进程ps -ef
  2. 当前进程的启动目录process.cwd()
  3. 改变工作目录process.chdir()
  4. 标准流process.stdin process.stdout process.stderr
  5. child_process.fork 与 POSIX 的 fork 有什么区别? Nodejs 的 child_process.fork()在 UNIX 上的实现最终调用了 POSIX 的 fork,但是 POSIX 需要手动管理子进程的资源释放,child_process.fork 不用担心这个问题,nodejs 自动释放,并且可以在 option 中选择父进程死后是否允许子进程存活spawn exec fork
  6. child.kill 与 child.send一个是基于信号系统, 一个是基于 IPC.
  7. 父进程或子进程的死亡是否会影响对方? 什么是孤儿进程?子进程死亡不会影响父进程, 不过子进程死亡时(线程组的最后一个线程,通常是“领头”线程死亡时),会向它的父进程发送死亡信号.反之父进程死亡, 一般情况下子进程也会随之死亡,但如果此时子进程处于可运行态、僵死状态等等的话, 子进程将被进程 1(init 进程)收养,从而成为孤儿进程.另外, 子进程死亡的时候(处于“终止状态”),父进程没有及时调用 wait() 或 waitpid() 来返回死亡进程的相关信息,此时子进程还有一个 PCB 残留在进程表中,被称作僵尸进程.

Cluster

Cluster 是 nodejs 常见的利用多核的办法,它是利用 child_process.fork 实现的,所以 cluster 产生的进程之间是通过 IPC 来通信的,并且它也没有拷贝父进程的空间,而是通过加入 cluster.isMaster 来区分父、子进程。

const cluster = require('cluster')
const http = require('http')
const numCPUs = require('os').cpus().length

if (cluster.isMaster) {
   // 仅父进程执行
   // fork workers
   for(i = 0; i<numCPUs;i++) {
      cluster.fork()
   }
   cluster.on('exit', (worker) => {
      console.log(`worker ${worker.process.pid} died`)
   })
} else {
   // 仅子进程执行
   // workers can share any TCP connection
   http.createServer((req, res) => {
      res.writeHead(200)
      res.end('hello world')
   }).listen(3000)
}
复制代码

Koa

compose:

function compose(middlewares){
   return ctx => {
      const dispatch = i => {
         const middleware = middlewares[i]
         if(!middleware) return
         return middleware(ctx, () => dispatch(i+1))
      }
      return dispatch(0)
   }
}
复制代码

Context: ctx

class Context{
   constructor(req, res) {
      this.req=req
      this.res=res
   }
}
复制代码

Koa-mini

class Application() {
   constructor() {
      this.middlewares = []
   }
   listen(...args) {
      const server = http.createServer(async (req,res) => {
         const ctx = new Context(req,res)
         const fn = compose(this.middlewares)
         await fn(ctx)

         ctx.res.end(ctx.body)
      })
      server.listen(...args)
   }
   use(middleware){
      this.middlewares.push(middleware)
   }
}
复制代码

如果你现在也想学习前端开发技术,在学习前端的过程当中有遇见任何关于学习方法,学习路线,学习效率等方面的问题,你都可以加入到我的Q群中:前114中6649后671,里面有许多前端学习资料以及2020大厂面试真题 点赞、评论、转发 即可免费获取,希望能够对你们有所帮助。


Tags:

最近发表
标签列表