客户端容器 | 字节青训营

161 阅读14分钟

1. 浏览器架构

1.1 浏览器架构演进

  • 单进程架构: 所有模块运行在同一个进程里,包含网络、插件、JavaScript运行环境等
  • 多进程架构:主进程、网络进程、渲染进程、GPU进程、插件进程
  • 面向服务架构: 将原来的UI、数据库、文件、设备、网络等,作为一个独立的基础服务.

image.png

1.2 浏览器架构对比

image.png

在单进程架构下,JavaScript运行环境与浏览器的其他模块(例如网络、插件等)都运行在同一个进程中。这意味着,如果JavaScript运行环境出现问题(例如内存泄漏、死循环等),可能会影响整个浏览器的稳定性。

1.3 浏览器任务管理器

浏览器的任务管理器类似于操作系统的任务管理器,用来查看浏览器中各个进程和标签页的资源占用情况,例如CPU、内存、网络等。

Chrome浏览器中,点击菜单按钮(三个竖点),然后选择“更多工具”->“任务管理器”,来打开浏览器的任务管理器。 image.png

1.4 多进程分工

浏览器是多进程的,

  • 常见的进程有browser进程(主进程,用来管理浏览器,协调主控以及页面的前进后退等功能).
  • GPU进程(3D绘制,最多一个)。
  • 第三方插件进程(每种类型的插件对应一个进程,使用到的时候创建)。
  • 浏览器渲染进程(默认每个Tab页面一个进程,互不影响,控制页面渲染,脚本执行,事件处理等(有时候会优化,如多个空白tab会合并成一个进程))。

这里补充一下关于javascript运行环境的解释

JavaScript运行环境指的是浏览器中负责执行JavaScript代码的部分。它包括JavaScript引擎(例如V8、SpiderMonkey等),以及提供给JavaScript代码访问的各种API(例如DOM API、Web API等)。

image.png

1.5 思考

  1. 为什么会有单进程架构?
  • 单进程架构:早期受到硬件的限制,内存十分昂贵,单进程可以节约系统资源。
  1. 面向服务架构是否会替代多进程架构?
  • 面向服务架构是谷歌2016年在多进程的上面进行演进,优势在于可以自动调节架构。比如:在设备比较好的,会做成面向服务架构,性能比较差的机器上,会做成多进程架构,也是为了节约资源。

2. 渲染进程

2.1 常见的浏览器内核(面试常问)

image.png

2.2 渲染进程的多线程架构

内部是多线程实现,主要负责页面渲染,脚本执行,事件处理,网络请求等。 渲染进程:内部是多线程的实现,其中包括

1、GUI渲染线程 (与JS引擎线程互斥)

2、JS引擎线程

3、定时器线程

4、事件触发线程

5、网络请求执行线程 image.png

2.3 JS引擎和渲染引擎

  1. 解析执行JS
  2. XML解析生成渲染树,显示在屏幕
  3. 桥接方式通信 image.png

2.3.1 js引擎、渲染引擎执行流程

JS引擎:

  • 解析执行JS,当我们拿到JS源码(文本),通过JS引擎(解释器)进行解析,生成语法树,翻译为操作系统可以执行的字节码,
  • v8优化:高频的函数,会转为机器码,转为机器码的好处就是下次可以直接执行,不需要像字节码一样解析执行,由此达到优化效果。

渲染引擎:

  • HTML和CSS也是文本,根据XML解析器解析生成DOM树,CSS解析器会解析CSS样式,并将样式信息附加到DOM树上,生成渲染树。
  • CSS解析可以与HTML解析同进行,布局render树,绘制render树(paint),绘制页面像素信息。

JS引擎和渲染引擎相互独立,如果我们想通过js操作DOM,其实是通过JSbridge操作的,因为需要通信是有一定延迟的

ps: JsBridge是一种通信方式,它允许JavaScript和原生应用之间进行通信。在Webview中,JsBridge可以实现JavaScript操作DOM。在原生应用中,前端和原生之间也可以通过JsBridge进行通信。

2.4 多线程的工作流程

  1. 网络线程负责加载网页资源
  2. JS引擎解析JS脚本并且执行
  3. JS解析引擎空闲时,渲染线程立即工作
  4. 用户交互、定时器操作等产生回调函数放入任务队列中
  5. 事件线程进行事件循环,将队列里的任务取出交给JS引擎执行

image.png

练习题

const now = Date. now( )
    setTimeout(() => {
    console. log('time10', Date.now() - now)
},10)

setTimeout(() => {
    console. log('time30', Date.now() - now)
},30)

while (true) {
    if (Date.now()- now>=20) {
        break
    }
}

console. log(Date. now() - now) // 输出? ?

image.png

3. Chrome运行原理

3.1 如何展示网页(面试常问)

image.png

3.2 输入处理

  1. 用户Url框输入内容的后,UI线程会判断输入的是一个URL地址呢,还是一个query查询条件
  2. 如果是URL,直接请求站点资源
  3. 如果是query,将输入发送给搜索引擎

3.3 开始导航

当用户按下回车,UI线程通知网络线程发起一个网络请求,来获取站点内容 2. 请求过程中,tab处于loading状态

image.png

3.4 读取响应

  1. 网络线程接收到HTTP响应后,先检查响应头的媒体类型 (MIME Type
  2. 如果响应主体是一个HTML文件,浏览2.器将内容交给渲染进程处理
  3. 如果拿到的是其他类型文件,比如Zip.exe等,则交给下载管理器处理

image.png

3.4 寻找渲染进程

  1. 网络线程做完所有检查后,会告知主进程数据已准备完毕,主进程确认后为这个站点寻找一个渲染进程 2.主进程通过IPC消息告知渲染进程去处理本次导航
  2. 渲染进程开始接收数据并告知主进程自己已开始处理,导航结束,进入文档加载阶段。

3.4 资源加载

  1. 收到主进程的消息后,开始加载HTML文档
  2. 除此之外,还需要加载子资源,比如一些图片,CSS样式文件以及JavaScript脚本。

image.png

3.5 构建渲染树

  1. 构建DOM树,将HTML文本转化成浏览器能够理解的结构
  2. 构建CSSOM树,浏览器同样不认识CSS,需要将CSS代码转化为可理解的CSSOM
  3. 构建渲染树,渲染树是DOM树和CSSOM树的结合。

image.png

3.6 页面布局

  1. 根据渲染树计算每个节点的位置和大小
  2. 在浏览器页面区域绘制元素边框
  3. 遍历渲染树,将元素以盒模型的形式写入文档流

image.png

3.7 页面绘制

  1. 构建图层:为特定的节点生成专用图层
  2. 绘制图层: 一个图层分成很多绘制指然后将这些指令按顺序组成一个水绘制列表,交给合成线程

image.png

  1. 合成线程接收指令生成图块。
  2. 栅格线程将图块进行栅格化。
  3. 展示在屏幕上。

image.png

4. 前端性能的performance

image.png

4.1 首屏优化

  1. 压缩、分包、删除无用代码
  • 压缩:指使用特定的算法来压缩网页中的资源文件(如 HTML、CSS、JavaScript 和图片等),以减小文件大小,加快加载速度。例如,可以使用 Gzip 或 Brotli 等压缩算法来压缩文本文件,使用 PNGquant 或 JPEGmini 等工具来压缩图片。

  • 分包:指将网页中的资源文件分成多个包,按需加载。这样,用户在访问网页时只需要加载首屏所需的资源文件,而不必一次性加载所有文件。例如,可以使用 Webpack 或 Rollup 等打包工具来实现代码分包。

  • 删除无用代码:指删除网页中不再使用的代码和资源文件,以减小文件大小,加快加载速度。例如,可以使用 UglifyJS 或 Terser 等工具来删除 JavaScript 代码中的无用代码,使用 PurgeCSS 等工具来删除 CSS 代码中的无用样式。

  1. 静态资源分离
  • 静态资源分离是指将网页中的静态资源(如图片、CSS、JavaScript 等)与网页本身分开存储,通常放在 CDN(内容分发网络)上。这样,当用户访问网页时,浏览器可以从最近的 CDN 节点获取静态资源,加快加载速度。

  • 当静态资源与网页本身位于同一个域名下时,浏览器在获取静态资源时会默认携带网页的 cookie。这是因为浏览器会将同一个域名下的所有请求视为同源请求,自动携带 cookie。

  1. JS脚本非阻塞加载
  • 使用XMLHttpRequest对象异步方式加载外部脚本。
  • 使用Javascript来动态创建外部脚本的SCRIPT元素
  • 使用Script标签的 derfer 属性
  • docuument.write script tag
  1. 缓存策略
  • 通过文件内容生成content hash是一种常用的缓存策略。它可以根据静态文件(如CSS,JS,图片)的内容生成对应的HASH值作为它的版本号,当文件内容发生变化时,版本号也会随之变化。这样可以有效地解决浏览器缓存问题。文件不变可以使用缓存hash。

  • 例如,可以使用gulp来实现这个功能。它可以通过对js和css文件内容进行hash运算,生成一个文件的唯一hash字符串,然后替换html中的js和css文件名,生成一个带版本号的文件名。

  1. SSR
  • 服务端渲染(SSR)指的是将组件在服务端直接渲染成HTML字符串,作为服务端响应返回给浏览器,最后在浏览器端将静态的HTML“激活”为能够交互的客户端应用。

  • 与客户端的单页应用(SPA)相比,SSR的优势主要在于更快的首屏加载和更好的SEO。但使用SSR时也有一些权衡之处需要考量,例如开发中的限制、更多的与构建配置和部署相关的要求以及更高的服务端负载

  1. 预置loading、骨架屏 预制loading和骨架屏都是用来提高用户体验的技术。它们可以在页面加载时给用户一个提示,让用户知道页面正在加载。

实现骨架屏的方法有很多,例如可以利用图片切换实现骨架屏效果,也可以利用CSS和HTML实现骨架屏效果。此外,还可以通过预渲染手动书写的代码生成相应的骨架屏,

4.2 渲染优化

  1. GPU加速
  • 透明度,transfom做动画,使用GPU加速一般会新建图层,会比较耗时,属性will-change ,提前告诉浏览器这个元素需要GPU加速,然后他会把元素放到新建的涂层里。
  • 可以给元素设置 transform 或 will-change 属性,告诉浏览器这个元素需要 GPU 加速。

例如,可以使用以下 CSS 代码来启用 GPU 加速:

.accelerate {
  transform: translateZ(0);
  will-change: transform;
}

//需要注意的是,并不是所有情况下都需要启用 GPU 加速。
//过多地使用 GPU 加速可能会导致内存占用过高,反而降低性能。
//因此,在使用 GPU 加速时应当谨慎。
  1. 减少回流、重绘。
  • transfom代替left,top,display:none设置元素可见不可见会引起回流,可以使用visibilty替代。
  • 尽量不要使用table布局,很大的表单,里面任何东西改了都会重新渲染,消耗较高。
  1. 离屏渲染
  • 开辟一块缓存区(内存),先进行渲染,完成渲染在显示到屏幕上。
  1. 懒加载
  • 将需要的资源提前加载到本地,直接从缓存里去拿。

4.3 Js优化

  1. 防止内存泄漏
  • 当我们使用全局变量时,有风险。日常开发在严格模式下,辅助工具的情况下,可以检测到一些泄露风险问题,

  • 比如有一些dom,我们将把它赋值给js变量,当dom被删除,js变量还没有被清空,并且DOM占用内存很大,需要手动删除。

  • 定时器,忘记清除也会导致内存泄露。

  1. 循环尽早break

  2. 合理使用闭包

  • 正确的使用闭包,可以减少元素的创建,在我们使用单例的时候,闭包函数创建,即使调用多次也只创建一个变量。
  1. 减少Dom访问
  • js引擎和渲染引擎交互比较费时间。减少访问次数,style,className形式,可以用变量缓存起来。不要每次都去window查询。
  1. 防抖、节流
  • 防抖:防止多次提交,只会提交最后一次。应用:input 输入查询搜索、scroll 滚动、表单验证、按钮提交。
  • 节流:规定时间内,多次调用也只会执行一次。dom 拖拽功能的实现、计算鼠标移动的距离、监听scroll滚动。
  1. Web Workers
  • 新的浏览器支持的属性。js引擎相互独立,它在执行时不会阻塞浏览器渲染,有问题是传输是文本传输,大的数据传输也会有性能问题,优点是:ArrayBuffer可以直接传输,图片视频,音频处理上。

5. 跨端容器

  • 跨端开发是指使用一种技术或方案来开发能够在多个平台(如iOS、Android和Web)上运行的应用程序。
  • 使用跨端开发可以帮助降低成本和提高开发效率。开发者只需编写一份代码,就可以在多个平台上运行。

5.1为什么需要跨端

  1. 开发成本、效率。
  2. 一致性体验。
  3. 前端开发生态。

image.png

5.2 有哪些跨端方案

5.2.1 webview

  • Webview,即网页视图,用于加载网页Url,并展示其内容的控件。
  • 可以内嵌在移动端App内,实现前端混合开发,大多数混合框架都是基于Webview的二次开发,比如lonic、Cordova。
  • 常用webview,Android,IOS、国产Android image.png
  1. 使用webview的优势
  • 一次开发,处处使用,学习成本低。
  • 随时发布,即时更新,不用下载安装包。
  • 移动端设备性能不断提升,性能有保障,
  • 通过jsBridge和原生系统交互,实现复杂功能。
  1. webview使用原生能力

    2.1 javascript调用native

    • 注入 API:native获取js环境上下文对其挂载的对象或方法进行拦截。
    • 使用Webview URL Scheme 跳转拦截。
    • IOS上 window webkit messageHandler 直接通信。

    2.2 Native调用 Javascript

    • 直接通过webview 暴露的 API 执行JS代码
    • IOS webview.stringByEvaluatingJavaScriptFromString
    • Android webview.evaluateJavascript
  2. 跨端容器-WebView<->Native 通信

    • JS环境中提供通信的JSBridge
    • Native 端提供 SDK 响应JSBridge 发出的调用前端和客户端分别实现对应功能模块
      image.png

5.2.2 小程序

双线程的方案,数据层和渲染层进行分开 image.png

5.2.3 RN/ WeeX

image.png

5.2.4 Lynx

image.png

5.2.5 Flutter

Flutter是一个移动应用程序SDK,用于构建高性能、高保真的iOS和Android应用程序。Flutter中的Widget是构建应用程序用户界面的基本构建块。它们描述了应用程序在给定时刻应该呈现什么样子,并且可以响应用户交互。

Dart VM是Dart语言的虚拟机。它提供了一个即时编译器(JIT)和增量重新编译(支持热重载),实时度量收集(支持DevTools)和丰富的调试支持。当应用程序准备部署到生产环境时,Dart的预先编译(AOT)编译器可以将代码编译为本地ARM或x64机器代码,以便在移动设备或桌面计算机上运行。

Skia是一个开源的2D图形库,用于绘制文本、几何图形和图像。它提供了一组通用的API,可以在多种硬件和软件平台上使用。Skia被广泛应用于多种操作系统和应用程序中,包括Android、Chrome和Chrome OS。

image.png

5.3跨端容器-通用原理

  1. UI组件
  2. 染引擎
  3. 逻辑控制引擎
  4. 通信桥梁
  5. 底层API抹平表现差异

image.png

5.3.1 跨端方案对比

image.png

image.png