目录

本文阐述的内容为,在js的世界中,进程、线程、协程以及EventLoop的存在

概念

进程process

进程是程序执行的实例,程序只是一些指令的描述集合,一个CPU总是运行一个进程。

不同的进程之间不能通信,拥有独立的内存,是操作系统进行资源分配和调度的一个独立单位。

线程Thread

进程是线程的容器,一个进程中有一个或多个线程。线程是独立调度和分派的基本单位,换句话说是程序执行的最小单位,而进程是操作系统中资源分配的最小单位。

wiki进程wiki线程

举个例子

chrome浏览器,新开一个tab就是新开一个进程,一个tab打开的一个网页,里面有js引擎执行、http请求、页面渲染等,这些被称为线程。

新开一个tab的本质也就是新建一个浏览器实例,这说明浏览器内核是多线程的,浏览器的常驻线程有

协程Coroutine

由于在浏览器的js的世界中,它的存在微弱,我似乎都不曾听说过这个概念。理解它,常常需要借助子程序的概念,也就是纯函数,纯函数我们知道,只有入参出参,内部无副作用,一旦执行完毕,该函数就会被销毁。

而协程呢?在一个协程里,一个入参出参结束后,又会进入到下一个入参中。

协程有点像函数,又有点像线程。它的运行流程大致如下

用es6的Generator函数来举例子

function* gen(x){
  var y = yield x + 2
  return y
}

var g = gen(1)
g.next() // { value: 3, done: false }
g.next(2) // { value: 2, done: true }

流程为

它可以中断程序的执行,协程的切换由用户手动来控制,就好比说,切换线程由用户切换的一样。

协程的作用是什么?

由于我几乎不怎么用,不能体会到,但我想,在浏览器的js世界里,优化代码组织结构?

参考,协程的好处有哪些?Generator 函数的含义与用法

事件循环EventLoop

如果要以线程的概念来理解,应该是这样的

我们常说的js单线程,是指v8引擎单线程,因为它是解析运行js代码的主线程。

结合事件循环机制的概念,在js中,分为同步异步任务,同步任务在主线程中(也就是v8引擎),形成执行栈

异步任务会被添加到任务队列中(那谁去处理这个添加呢?就是这些子线程),当主线程中的执行栈为空时,就从异步任务队列(回调函数组成)里取回调执行。这个重复的过程,就称为事件循环。

另外,任务队列又分为macromicro,中文上我称之为

在任务队列中,也是有执行顺序的,分2种情况

分别举例子

例子1:

console.log('main thread 1')
setTimeout(() => {
    console.log('macro task')
}, 0)   // 严格意义上来讲,这个0是不可能的,规范上最小为10ms,浏览器会默认以10来处理

new Promise(res => {
    console.log('main thread 2')
    res()
}).then(() => {
    console.log('micro task')
})

例子2,基于例子1修改,新增任务即可:

console.log('第一次循环中的 main thread 1')
setTimeout(() => {
    // 添加到下一次的任务队列
    setTimeout(() => {
       console.log('第二次循环中的 macro 2')
    }, 0)

    // 添加到本次循环的任务队列
    new Promise(res => {
        console.log('第一次循环中的 macro 1')
        res()
    }).then(() => {
        console.log('第一次循环中的 micro 3')
    })
}, 0)

new Promise(res => {
    console.log('第一次循环中的 main thread 2')
    res()
}).then(() => {
    // 添加到下一次的任务队列
    setTimeout(() => {
        console.log('第二次循环中的 macro 1')
    }, 0)

    // 添加到本次循环的任务队列
    new Promise(res => {
        console.log('第一次循环中的 micro 1')
        res()
    }).then(() => {
        console.log('第一次循环中的 micro 2')
    })
})

setTimeout(() => {
  console.log('第一次循环中的 macro 2')
}, 0)

参考