v8垃圾回收机制

lies

v8垃圾回收机制

进程还是线程

To be or not

作为预备知识,首先需要了解什么是进程,什么是线程,举个简单例子,我们常说的杀死一个软件的进程,这个就是进程,进程相当于一个工厂,奴役着一个个的工人为之干活,工厂之间相互独立,每个工厂拥有独立的员工,每个进程拥有独立的线程,在此基础上线程就很好理解了,就是被奴役的工人,同一家公司下不同员工之间共享公司提供的资源,同理进程下的线程也共享进程的资源

浏览器是多进程的

这一点很容易得到验证,在windows/mac中的powershell/shell可以很清楚的看到,新开一个chrome tab页面,上面会多出一个进程,简单点理解,每打开一个 Tab 页,就相当于创建了一个独立的浏览器进程。

单线程的

JavaScript

优势,由于js的用途主要是与用户互动,以及操作dom,注定了他只能是单线程的,否则会带来很复杂的同步问题,倘若两个线程同时在操作dom,该听谁的好呢

劣势,由于js的是单线程的,这注定了js做事情只能一步一步的往下做,在js短暂的一生中他明白了一个道理,越是努力工作,就越是会被各种各样的不定时任务拖累,除非。。。。我设计一个任务处理模型来优化对不同任务的处理

事件循环机制

Event Loop

我们迟早会明白一个道理,处理不同事件或任务的时候,设计出一个高效的计划和方案,是如此的能提高工作效率和减少摸鱼情况的发生

js中对这些事件进行了简单的归类,其中有同步事件,还有异步事件, 举个简单的例子,我早上起来先烧个水,然后换衣服刷牙洗脸,等水烧开了喝水, 烧水就是异步事件,因为水没那么快烧完,我不可能等水烧完才做其他事情,否则一天都要这样被摸鱼摸没了

js在主线程中一行一行代码往下执行,遇到同步事件,则进入主线程直接执行,在这个过程中如果遇到一个异步事件,则将其推入事件表Event table并注册函数,当这个异步事件完成可以执行时,将其移入任务队列Event queue,当主线程执行栈call stack中的事件为空时,就会去读取事件队列,去执行对应的回调

宏任务和微任务

js中的任务类型分为两种,macrotask和microtask,在ECMAScript中,microtask称为jobs,macrotask称为task

  • 1. macrotask,又称为宏任务,可以理解为,每次执行栈执行的代码就是一个宏任务,包括每次从事件队列中获取一个事件回调并放到执行栈中执行,这里事件队列中每一个事件都是一个macrotask
  • 2. microtask,又称为微任务,可以理解是在当前task执行结束后立即执行的任务

宏任务,微任务的产生

  • macrotask:主代码块,setTimeout,setInterval等(可以看到,事件队列中的每一个事件都是一个macrotask)
  • microtask:Promise,process.nextTick等

宏任务,微任务的运行机制

  • 1. 执行一个宏任务(执行栈中没有就从事件队列中获取)
  • 2. 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
  • 3. 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
  • 4. 当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染
  • 5. 渲染完毕后,JS线程继续接管,开始下一个宏任务(从事件队列中获取)

你的任务

不,是你的任务

看下面的例子

console.log(0)
setTimeout(() => {
  console.log('s0')
})
console.log(1)
setTimeout(() => {
  Promise.resolve()
    .then(function() {
      console.log('promise1')
    })
    .then(function() {
      console.log('promise2')
    })
})
setTimeout(() => {
  console.log('s1')
})
console.log(2)

按之前的逻辑,代码的执行顺序应该是

  • 1. 首先整个代码块script中的代码是一个macrotask
  • 2. 执行过程中,遇到seTimeout则推入任务队列,过程中输出0,1,2
  • 3. 第一个macrotask执行完毕,此事从任务队列中获取一个macrotask执行,并输出s0
  • 4. 第二个macrotask执行完毕,此事从任务队列中获取一个macrotask执行,执行中产生microtask
  • 5. 第三个macrotask执行完毕,在第四个macrotask之前读取所有的microtask并执行,输出promise1,promise2,然后执行第四个macrotask,输出s1