浏览器原理简介

260 阅读6分钟

不涉及V8和垃圾回收以及F12相关

image.png

进程和线程的联系和区别

进程:当我们启动某个程序时,操作系统会给该进程创建一块内存(当程序关闭时,该内存空间就会被回收),用来存放代码、运行中的数据和一个执行任务的主线程,这样的一个运行环境就叫进程。

线程:线程是依附于进程的,在进程中使用多线程并行处理能提升运算效率,进程将任务分成很多细小的任务,再创建多个线程,在里面并行分别执行。

进程和线程的关系特点是这样的:

  • 进程与进程之间完全隔离,互不干扰,一个进程崩溃不会影响其他进程,避免一个进程出错影响整个程序

  • 进程与进程之间需要传递某些数据的话,就需要通过进程通信管道 IPC 来传递

  • 一个进程中可以并发多个线程,每个线程并行执行不同的任务

  • 一个进程中的任意一个线程执行出错,会导致这个进程崩溃

  • 同一进程下的线程之间可以直接通信和共享数据

  • 当一个进程关闭之后,操作系统会回收该进程的内存空间

Chrome 打开一个页面有多少进程?分别是哪些

浏览器从关闭到启动,然后新开一个页面至少需要:1个浏览器进程,1个 GPU 进程,1个网络进程,和一个渲染进程,一共4个进程。

后续如果再打开新的标签页:浏览器进程,GPU 进程,网络进程是共享的,不会重新启动,然后默认情况下会为每一个标签页配置一个渲染进程,但是也有例外,比如从A 页面里面打开一个新的页面B 页面,而 A 页面和B 页面又属于同一站点的话,A 和 B 就共用一个渲染进程,其他情况就为 B 创建一个新的渲染进程。

所以最新的 Chrome 浏览器包括:1个浏览器主进程,1个 GPU 进程,1个网络进程,多个渲染进程,和多个插件进程

  • 浏览器进程:负责控制浏览器除标签页外的界面,包括地址栏、书签、前进后退按钮等,以及负责与其他进程的协调工作,同时提供存储功能

  • GPU 进程:负责整个浏览器界面的渲染。Chrome 刚开始发布的时候是没有 GPU 进程的,而使用 GPU 的初衷是为了实现3D css 效果,只是后面的网页、Chrome 的 UI 界面都用 GPU 来绘制,这使 GPU 成为了浏览器普遍的需求,最后 Chrome 在多进程架构上也引入了 GPU 进程

  • 插件进程:主要是负责插件的运行,因为插件可能崩溃,所以需要通过插件进程来隔离,以保证插件崩溃也不会对浏览器和页面造成影响。

  • 渲染进程:负责控制显示 tab 标签页内的所有内容,核心任务是将 HTML、CSS、JS 转为用户可与之交互的网页,排版引擎 Blink和 JS 引擎 V8都是运行在该进程中,默认情况下 Chrome 会为每个 Tab 标签页创建一个渲染进程。

  • 网络进程:负责发起和接受网络请求,以前是作为一个模块运行在浏览器进程里面,后面才独立出来,成为一个单独的进程。

  • 音频进程:浏览器音频管理

我们平时看到的浏览器呈现出页面过程中,大部分工作都是在渲染进程中完成,所以我们来看一下渲染进程中的线程

渲染进程中的线程

  • GUI渲染线程:负责渲染页面,解析 html 和 CSS、构建 DOM 树、CSSOM 树、渲染树、和绘制页面,重绘重排也是在该线程执行

  • JS 引擎线程:一个 tab 页中只有一个 JS 引擎程(单线程),负责解析和执行 JS。它 GUI 渲染进程不能同时执行,只能一个一个来,如果JS 执行过长就会导致阻塞掉帧

  • 计时器线程:指 setInterval 和 setTimeout,因为 JS 引擎是单线程的,所以如果处于阻塞状态,那么计时器就会不准了,所以需要单独的线程来负责计时器工作

  • 异步 http 请求线程:XMLHttpRequest 连接后浏览器开的一个线程,比如请求有回调函数,异步线程就会将回调函数加入事件队列,等待 JS 引擎空闲执行

  • 事件触发线程:主要用来控制事件循环,比如 JS 执行遇到计时器,AJAX 异步请求等,就会将对应任务添加到事件触发线程中,在对应事件符合触发条件触发时,就把事件添加到待处理队列的队尾,等 JS 引擎处理

你知道哪些进程间通信的方式?

  • 管道通信:就是操作系统在内核中开辟一段缓冲区,进程1可以将需要交互的数据拷贝到这个缓冲区里,进程2就可以读取了

  • 消息队列通信:消息队列就是用户可以添加和读取消息的列表,消息队列里提供了一种从一个进程向另一个进程发送数据块的方法,不过和管道通信一样每个数据块有最大长度限制

  • 共享内存通信:就是映射一段能被其他进程访问的内存,由一个进程创建,但多个进程都可以访问,共享进程最快的是IPC方式

  • 信号量通信:比如信号量初始值是1,进程1来访问一块内存的时候,就把信号量设为0,然后进程2也来访问的时候看到信号量为0,就知道有其他进程在访问了,就不访问了

  • socket:其他的都是同一台主机之间的进程通信,而在不同主机的进程通信就要用到socket的通信方式了,比如发起http请求,服务器返回数据

image.png

多标签之间怎么通信?

没有办法直接通信,需要有一个类似中介者进行消息的转发和接收,比如

  • localStorage:在一个标签页监听localStorage的变化,然后当另一个标签页修改的时候,可以通过监听获取新数据

当然只能同域名的情况下数据才能共享,不同域名之间不能共享数据 ; sessionStorage 是会话级别的,不可以

  • WebSocket:因为websocket可以实现实时服务器推送,所以服务器就可以来当这个中介者。标签页通过向服务器发送数据,然后服务器再向其他标签推送转发
  • ShareWorker:会在页面的生命周期内创建一个唯一的线程,并开启多个页面也只会使用同一个线程,标签页共享一个线程
  • postMessage
// 发送方 
window.parent().pastMessage('发送的数据','http://接收的址') 
// 接收方 
window.addEventListener('message',(e)=>{ let data = e.data })