Skip to content

浏览器运行机制

浏览器内核

  • Chrome, Safari: webkit
  • firefox: Gecko
  • IE: Trident
  • 360: webkit + Trident

重要内核模块

进程:程序的一次执行,占用独立的内存空间。

线程:进程内的一个独立执行单元,共享进程的内存空间。

  • js 引擎:负责 js 编译与运行(主线程)
  • 文档(html/css)解析模块:负责文本解析(主线程)
  • DOM/CSS模块:负责 DOM/CSS 树(主线程)
  • 布局和渲染模块:负责页面布局和绘制(主线程)
  • 事件响应模块(子线程)
  • 定时器模块(子线程)
  • 网络请求模块(子线程)

JS引擎

  • 处理 JavaScript 脚本的虚拟机,如 Chrome 的 V8 引擎
  • 内存分配发生的地方
  • 函数调用时会形一个个栈帧(frame)

JS是单线程的

JS is single-threaded,which does only one thing at a given time.

  • JS 只有一个主线程,一次只能执行一段代码。
  • 浏览器是事件驱动的,浏览器中很多行为是异步的,会创建事件并放入执行队列中。
  • 一个浏览器至少实现三个常驻线程:
    1. JS 引擎线程
    2. GUI 渲染线程
    3. 事件触发线程

执行栈

  1. 函数执行时,会生成新的 execution context(执行上下文),推入执行栈中
  2. running execution context(正在执行的上下文)始终处于栈顶
  3. 函数执行完后,它的执行上下文会从栈弹出

事件循环与任务队列

  • Event Loop是由javascript宿主环境(像浏览器)来实现的;
  • WebAPIs是由C++实现的浏览器创建的线程,处理诸如DOM事件、http请求、定时器等异步事件;
  • JavaScript 的并发模型基于"事件循环";
  • Callback Queue(Event Queue 或者 Message Queue) 任务队列,存放异步任务的回调函数 x

事件循环

"Event Loop is a programming construct that waits for and dispatches events or messages in a program."

涉及两个线程:一个负责程序本身的运行,称为 主线程;一个负责主线程与其他进程(主要各种I/O操作)的通信,被称为 Event Loop 线程 或消息线程。

  1. 函数入栈,当Stack中执行到异步任务的时候,就将他丢给WebAPIs,接着执行同步任务,直到Stack为空;
  2. 在此期间WebAPIs完成这个事件,把回调函数放入CallbackQueue中等待;
  3. 当执行栈为空时,Event Loop把Callback Queue中的一个任务放入Stack中,回到第1步
// 例子
var start = new Date();
setTimeout(function cb(){
  console.log("时间间隔:", new Date() - start+'ms');
},500);
while(new Date() - start < 1000){};
  1. main(Script) 函数入栈,start变量开始初始化
  2. setTimeout入栈,出栈,丢给WebAPIs,开始定时500ms;
  3. while循环入栈,开始阻塞1000ms;
  4. 500ms过后,WebAPIs把cb()放入任务队列,此时while循环还在栈中,cb()等待;
  5. 又过了500ms,while循环执行完毕从栈中弹出,main()弹出,此时栈为空,Event Loop,cb()进入栈,log()进栈,输出'时间间隔:1003ms',出栈,cb()出栈

任务队列

  • 宏任务(Macrotasks)
    • setTimeout
    • setInterval
    • setImmediate
    • I/O
    • UI rendering
  • 微任务(Microtasks)
    • process.nextTick
    • promises
    • Object.observe
    • MutationObserver

https://www.cnblogs.com/wxcbg/p/11040362.html

async function async1() {
  console.log("async1 start");
  await async2();
  console.log("async1 end");
}

async function async2() {
  console.log( 'async2');
}

debugger
console.log("script start");

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

async1();

console.log("script middle");

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

乱入

// 宏任务
requestAnimationFrame(() => console.log('requestAnimationFrame 执行'));

// 宏任务
setTimeout(() => console.log('setTimeout 执行'));

// 微任务
Promise.resolve().then(() => console.log('Promise.resolve 执行'));

// 微任务
queueMicrotask(() => console.log('queueMicrotask 执行'));

谷歌浏览器的 queueMicrotask 类似 nodejs 的 process.nextTick