一、浏览器架构
(一)浏览器架构演进
单进程架构:所有模块都运行在一个进程里,包含网络、插件、javascript运行环境等
多进程架构:主进程、网络进程、GUI进程、渲染进程、插件进程。
面向服务架构:将原来的UI,数据库,文件、设备、网络等。作为一个独立的基础服务。
浏览器是多进程的,常见的进程有browser进程(主进程,用来管理浏览器,协调主控以及页面的前进后退等功能),GPU进程(3D绘制,最多一个),第三方插件进程(每种类型的插件对应一个进程,使用到的时候创建),浏览器渲染进程(默认每个Tab页面一个进程,互不影响,控制页面渲染,脚本执行,事件处理等(有时候会优化,如多个空白tab会合并成一个进程))。
这里补充一下关于javascript运行环境的解释
JavaScript运行环境指的是浏览器中负责执行JavaScript代码的部分。它包括JavaScript引擎(例如V8、SpiderMonkey等),以及提供给JavaScript代码访问的各种API(例如DOM API、Web API等)。
在单进程架构下,JavaScript运行环境与浏览器的其他模块(例如网络、插件等)都运行在同一个进程中。这意味着,如果JavaScript运行环境出现问题(例如内存泄漏、死循环等),可能会影响整个浏览器的稳定性。
(二)浏览器架构
浏览器架构-架构对比
浏览器架构-任务管理器
浏览器的任务管理器类似于操作系统的任务管理器,用来查看浏览器中各个进程和标签页的资源占用情况,例如CPU、内存、网络等。
Chrome浏览器中,点击菜单按钮(三个竖点),然后选择“更多工具”->“任务管理器”,来打开浏览器的任务管理器。
浏览器架构-多进程分工
浏览器采用多进程架构模型,通过进程之间的协作来实现网络请求、页面渲染、JavaScript 执行和 Web 安全防范等功能,并且提升了浏览器的稳定性、流畅性和安全性。
question1: 为什么会有单进程?
受到早期硬件的限制,内存比较贵。每个进程都会占用系统资源。
question2: 面向服务架构是否会替代多进程架构
应该会替代,
二、渲染进程
常见浏览器内核
渲染进程、多进程架构
渲染进程:内部是多线程的实现,其中包括
1、GUI渲染线程 (与JS引擎线程互斥)
2、JS引擎线程
3、定时器线程
4、事件触发线程
5、网络请求执行线程
对比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进行通信。
多进程的工作流程
练习题
以下代码在浏览器环境下输出顺序、内容
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) // 输出? ?
答案: 先输出console.log,打印20,然后执行第一个定时器中的输出,原则上输出会晚于20,但不会太久,最后是第二个定时器的输出打印大概30左右的数。
三、Chrome的运行原理
浏览器输入了URL后发生了什么?
输入处理
开始导航
读取响应
寻找渲染进程
资源加载
构建渲染树
页面布局
页面绘制
性能工具performance
首屏优化
一、压缩、分包、删除无用代码。
- 压缩:指使用特定的算法来压缩网页中的资源文件(如 HTML、CSS、JavaScript 和图片等),以减小文件大小,加快加载速度。例如,可以使用 Gzip 或 Brotli 等压缩算法来压缩文本文件,使用 PNGquant 或 JPEGmini 等工具来压缩图片。
- 分包:指将网页中的资源文件分成多个包,按需加载。这样,用户在访问网页时只需要加载首屏所需的资源文件,而不必一次性加载所有文件。例如,可以使用 Webpack 或 Rollup 等打包工具来实现代码分包。
- 删除无用代码:指删除网页中不再使用的代码和资源文件,以减小文件大小,加快加载速度。例如,可以使用 UglifyJS 或 Terser 等工具来删除 JavaScript 代码中的无用代码,使用 PurgeCSS 等工具来删除 CSS 代码中的无用样式。
2、静态资源分离
-
静态资源分离是指将网页中的静态资源(如图片、CSS、JavaScript 等)与网页本身分开存储,通常放在 CDN(内容分发网络)上。这样,当用户访问网页时,浏览器可以从最近的 CDN 节点获取静态资源,加快加载速度。
-
当静态资源与网页本身位于同一个域名下时,浏览器在获取静态资源时会默认携带网页的 cookie。这是因为浏览器会将同一个域名下的所有请求视为同源请求,自动携带 cookie。
-
示例:演示如何使用 CDN 来存储静态资源
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://cdn.example.com/css/style.css">
</head>
<body>
<h1>Hello World</h1>
<img src="https://cdn.example.com/img/logo.png" alt="Logo">
<script src="https://cdn.example.com/js/app.js"></script>
</body>
</html>
在这个例子中,我们使用了一个假设的 CDN 域名 cdn.example.com 来存储静态资源。我们在网页中引用了这个域名下的 CSS 文件、图片和 JavaScript 文件。
当用户访问这个网页时,浏览器会自动从 cdn.example.com 获取静态资源。由于这个域名与网页本身的域名不同,浏览器不会携带网页的 cookie。
3、js脚本非阻塞加载/放在底部
4、缓存策略。
-
通过文件内容生成content hash是一种常用的缓存策略。它可以根据静态文件(如CSS,JS,图片)的内容生成对应的HASH值作为它的版本号,当文件内容发生变化时,版本号也会随之变化。这样可以有效地解决浏览器缓存问题。文件不变可以使用缓存hash。
-
例如,可以使用gulp来实现这个功能。它可以通过对js和css文件内容进行hash运算,生成一个文件的唯一hash字符串,然后替换html中的js和css文件名,生成一个带版本号的文件名。
5、SSR服务端渲染
服务端渲染(SSR)指的是将组件在服务端直接渲染成HTML字符串,作为服务端响应返回给浏览器,最后在浏览器端将静态的HTML“激活”为能够交互的客户端应用。
与客户端的单页应用(SPA)相比,SSR的优势主要在于更快的首屏加载和更好的SEO。但使用SSR时也有一些权衡之处需要考量,例如开发中的限制、更多的与构建配置和部署相关的要求以及更高的服务端负载
6、预制loading,骨架屏。
预制loading和骨架屏都是用来提高用户体验的技术。它们可以在页面加载时给用户一个提示,让用户知道页面正在加载。
实现骨架屏的方法有很多,例如可以利用图片切换实现骨架屏效果,也可以利用CSS和HTML实现骨架屏效果。此外,还可以通过预渲染手动书写的代码生成相应的骨架屏,例如使用vue-skeleton-webpack-plugin插件,通过vueSSR结合webpack在构建时渲染写好的vue骨架屏组件,将预渲染生成的DOM节点和相关样式插入到最终输出的html中。
骨架屏效果的HTML和CSS代码示例:
<!-- HTML -->
<div class="skeleton">
<div class="skeleton-header"></div>
<ul class="skeleton-list">
<li></li>
<li></li>
<li></li>
</ul>
</div>
/* CSS */
.skeleton {
padding: 10px;
}
.skeleton-header {
height: 20px;
width: 30%;
margin-bottom: 10px;
background-color: #e0e0e0;
}
.skeleton-list li {
height: 20px;
margin-bottom: 10px;
background-color: #e0e0e0;
}
@keyframes shine {
from {
background-position: -100px;
}
to {
background-position: 140px;
}
}
.skeleton-header,
.skeleton-list li {
animation-duration: 1s;
animation-fill-mode: forwards;
animation-iteration-count: infinite;
animation-name: shine;
animation-timing-function: linear;
background-image: linear-gradient(
to right,
#e0e0e0 0%,
#f5f5f5 20%,
#e0e0e0 40%,
#e0e0e0 100%
);
}
这个示例中,我们使用HTML创建了一个简单的骨架屏结构,包括一个头部和一个列表。然后使用CSS定义了骨架屏中元素的样式,包括高度、宽度、外边距和背景颜色等。最后,使用CSS中的animation属性定义了一个简单的动画效果,让骨架屏看起来更加生动。
渲染优化
1、GPU加速。
透明度,transfom做动画,使用GPU加速一般会新建图层,会比较耗时,属性will-change ,提前告诉浏览器这个元素需要GPU加速,然后他会把元素放到新建的涂层里。
可以给元素设置 transform 或 will-change 属性,告诉浏览器这个元素需要 GPU 加速。
例如,可以使用以下 CSS 代码来启用 GPU 加速:
.accelerate {
transform: translateZ(0);
will-change: transform;
}
//需要注意的是,并不是所有情况下都需要启用 GPU 加速。
//过多地使用 GPU 加速可能会导致内存占用过高,反而降低性能。
//因此,在使用 GPU 加速时应当谨慎。
2、减少回流,重绘。transfom代替left,top,display:none设置元素可见不可见会引起回流,可以使用visibilty替代,尽量不要使用table布局,很大的表单,里面任何东西改了都会重新渲染,消耗较高。
3、离屏渲染。开辟一块缓存区(内存),先进行渲染,完成渲染在显示到屏幕上。
4、懒加载。将需要的资源提前加载到本地,直接从缓存里去拿。
JS优化
一、防止内存泄露。
-
当我们使用全局变量时,有风险。日常开发在严格模式下,辅助工具的情况下,可以检测到一些泄露风险问题,
-
比如有一些dom,我们将把它赋值给js变量,当dom被删除,js变量还没有被清空,并且DOM占用内存很大,需要手动删除。
-
定时器,忘记清除也会导致内存泄露。
二、循环尽早break.
三、合理使用闭包。
- 正确的使用闭包,可以减少元素的创建,在我们使用单例的时候,闭包函数创建,即使调用多次也只创建一个变量。
四、减少dom访问。
- js引擎和渲染引擎交互比较费时间。减少访问次数,style,className形式,可以用变量缓存起来。不要每次都去window查询。
五、防抖,节流。
-
防抖:防止多次提交,只会提交最后一次。应用:input 输入查询搜索、scroll 滚动、表单验证、按钮提交。
-
节流:规定时间内,多次调用也只会执行一次。dom 拖拽功能的实现、计算鼠标移动的距离、监听scroll滚动。
六、web work:
- 新的浏览器支持的属性。js引擎相互独立,它在执行时不会阻塞浏览器渲染,有问题是传输是文本传输,大的数据传输也会有性能问题,优点是:ArrayBuffer可以直接传输,图片视频,音频处理上。
对于大量数据,可以使用可转移对象(Transferrable Object)进行零拷贝传输。例如,可以使用以下代码将 ArrayBuffer 对象传输到 worker 线程:
var worker = new Worker('js2.js');
worker.postMessage(buffer, [buffer]);
四、跨端容器
为什么需要跨端
跨端开发是指使用一种技术或方案来开发能够在多个平台(如iOS、Android和Web)上运行的应用程序。使用跨端开发可以帮助降低成本和提高开发效率。开发者只需编写一份代码,就可以在多个平台上运行,
有哪些跨端方案?
webview:
- 网页视图,用于加载网页URL,展示其内容的控件,
- WebView提供了一种简单的方法来在原生应用中嵌入网页内容,可以让开发者利用Web技术(如HTML、CSS和JavaScript)来构建应用程序的一部分或全部功能。这样,开发者可以利用Web技术的优势,例如快速迭代、丰富的生态系统和跨平台能力,来提高开发效率和降低成本。
webview的分类
使用webview的优势
-
一次开发,处处使用,学习成本低。
-
随时发布,即时更新,不用下载安装包。
-
移动端设备性能不断提升,性能有保障,
-
通过jsBridge和原生系统交互,实现复杂功能。
webview使用原生能力
- js调用native
1、注入 API:native获取js环境上下文对其挂载的对象或方法进行拦截。
2、拦截 URL SCHEME:跳转拦截。
3、IOS上 window webkit messageHandler 直接通信。
- native调用js
1、直接通过webview暴露的api执行代码。
2、对于 iOS 的 UIWebView
result = [uiWebview stringByEvaluatingJavaScriptFromString:javaScriptString];
3、andriod: 使用loadUrl方法来执行一段JS代码,或者使用evaluateJavascript方法来执行一段JS函数。
可以这样调用一个名为myFunction的JS函数:
webView.loadUrl("javascript:myFunction()");
webview《==》通信
实现一个简易的JSbridge
小程序
RN/Week
Lynx
首屏幕渲染:相比RN/Week比较快,RN/Week的dom通过js创建的,虚拟dom,而Lynx的dom节点的计算放在了native层,js只关注业务逻辑,不会阻碍DOM渲染。jscore v8引擎,绑定
Flutter
Flutter是一个移动应用程序SDK,用于构建高性能、高保真的iOS和Android应用程序。Flutter中的Widget是构建应用程序用户界面的基本构建块。它们描述了应用程序在给定时刻应该呈现什么样子,并且可以响应用户交互。
Dart VM是Dart语言的虚拟机。它提供了一个即时编译器(JIT)和增量重新编译(支持热重载),实时度量收集(支持DevTools)和丰富的调试支持。当应用程序准备部署到生产环境时,Dart的预先编译(AOT)编译器可以将代码编译为本地ARM或x64机器代码,以便在移动设备或桌面计算机上运行。
Skia是一个开源的2D图形库,用于绘制文本、几何图形和图像。它提供了一组通用的API,可以在多种硬件和软件平台上使用。Skia被广泛应用于多种操作系统和应用程序中,包括Android、Chrome和Chrome OS。
通用原理
五、跨端方案对比
课程总结