homobulla / javascript-book

读书笔记
0 stars 0 forks source link

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

Open homobulla opened 6 years ago

homobulla commented 6 years ago

从浏览器多进程到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线程继续接管,开始下一个宏任务(从事件队列中获取)