Skip to content

从浏览器多进程到js单线程 #6

@homobulla

Description

@homobulla

从浏览器多进程到js单线程

URL(笔记来源): https://juejin.im/post/5a6547d0f265da3e283a1df7

进程与线程 进程是cpu资源分配的最小单位(系统会给它分配内存) 线程是cpu调度的最小单位

浏览器是多进程的,js是单线程的
进程是一个工厂,工厂有它的独立资源 ——> 系统分配的内存(独立的一块内存)
工厂之间的相互独立 -> 进程之间相互独立
多个工人协作完成任务 -> 多个线程在进程中协作完成任务
工厂内有一个或多个工人 -> 一个进程由一个或多个线程组成
工人之间共享空间 -> 同一进程下的各个线程之间共享程序的内存空间(包括代码段、数据集、堆等)

浏览器包含的进程

Browser进程:浏览器的主进程(负责协调、主控),只有一个。
第三方插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建
GPU进程:最多一个,用于3D绘制等
浏览器渲染进程(浏览器内核)

浏览器的渲染进程 ---> 多线程

浏览器渲染进程包含的线程

1. GUI渲染线程    
2. JS引擎线程
3. 事件触发线程
4. 定时触发器线程
5. 异步http请求线程
 
GUI渲染线程与JS引擎线程是互斥的. 当JS引擎执行时GUI线程会被挂起(相当于被冻结了),GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。
GUI渲染操作DOM,js操作也会操作DOM,为了防止二者冲突。JS引擎执行时间过长会阻塞页面。

web Worker

web worker 可以使得后台线程执行任务而不干扰页面。

   创建worker时,JS引擎开启一个子线程,且不能操作DOM.
JS引擎线程与worker线程通过 postMessage API 方式通信。

从Event Loop谈JS的运行机制

JS分为同步任务和异步任务
同步任务都在主线程上执行,形成一个 执行栈
主线程之外,事件触发线程管理着一个 任务队列 ,只要异步任务有了运行结果,就在任务队列之中放置一个事件。
一旦执行栈中的所有同步任务执行完毕(此时JS引擎空闲),系统就会读取任务队列,将可运行的异步任务添加到可执行栈中,开始执行。
 macrotask与microtask

    console.log('script start');

    setTimeout(function() {
        console.log('setTimeout');
    }, 0);

    Promise.resolve().then(function() {
        console.log('promise1');
    }).then(function() {
        console.log('promise2');
    });

    console.log('script end');

JS中分为两种任务类型:macrotask和microtask

macrotask:主代码块,setTimeoutsetInterval等(可以看到,事件队列中的每一个事件都是一个macrotask)

microtaskPromiseprocess.nextTick

一 `macrotask`(又称之为宏任务),可以理解是每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)
    1. 每一个task会从头到尾将这个任务执行完毕,不会执行其它.
    2. 浏览器为了能够使得JS内部task与DOM任务能够有序的执行,会在一个task执行结束后,在下一个 task 执行开始前,对页面进行重新渲染 (task->渲染->task->...)

二 `microtask`(又称为微任务),可以理解是在当前 task 执行结束后立即执行的任务
    1. 也就是说,在当前task任务后,下一个task之前,在渲染之前
    2. 所以它的响应速度相比`setTimeout`(`setTimeout`是task)会更快,因为无需等渲染
    3. 也就是说,在某一个`macrotask`执行完后,就会将在它执行期间产生的所有`microtask`都执行完毕(在渲染前)

macrotask中的事件都是放在一个事件队列中的,而这个队列由事件触发线程维护microtask中的所有微任务都是添加到微任务队列(Job Queues)中,等待当前macrotask执行完毕后执行,而这个队列由JS引擎线程维护(这点由自己理解+推测得出,因为它是在主线程下无缝执行的)

运行机制

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions