浏览器架构
浏览器架构演进
- 单进程架构:所有模块运行在同一个进程里,包含网络、插件、JavaScript运行环境等
在早期的浏览器中,所有的功能都在一个进程中完成,包括用户界面、JavaScript执行、CSS渲染和网络请求等。单进程架构的优势是简单、易于实现,但缺点也很明显,如:不稳定(一个标签页崩溃可能导致整个浏览器崩溃)、不安全(攻击者可以利用漏洞来控制整个浏览器)以及性能瓶颈(多个标签页争抢资源,导致性能下降)。
- 多进程架构:主进程、网络进程、渲染进程、GPU进程、插件进程
为了解决单进程架构的问题,浏览器厂商开始将浏览器的功能拆分为多个进程。例如,谷歌推出的Chrome浏览器就采用了多进程架构。在这种架构下,浏览器将每个标签页(或每个渲染实例)分配给一个单独的进程,从而实现了进程间的隔离,防止单个网页崩溃影响到其他界面。多进程架构提高了浏览器的稳定性、安全性和性能,但同时也增加了内存消耗。
每一个Tab运行在独立的沙盒里面。
- 面向服务架构:将原来的UI、数据库、文件、设备、网络等,作为一个独立的基础服务
面向服务架构是多进程架构的升级版本。
随着Web平台的发展,浏览器需要处理越来越多的任务,这使得多进程架构变得复杂且难以维护。面向服务架构的出现旨在将浏览器的各个功能模块化,将它们作为独立的服务来运行和维护。在这种架构下,每个服务都可以独立地使用一个或多个进程,根据需求自动扩展或缩减资源。这样可以进一步提高浏览器的稳定性、安全性和性能,同时优化资源利用率。
任务管理器
在多进程浏览器架构中,任务管理器是一个非常重要的组件。任务管理器负责监控、管理和分配浏览器的各个进程,确保整个浏览器系统的稳定性和性能。
任务管理器主要负责以下几方面的功能:
进程监控:任务管理器可以实时查看浏览器中的各个进程,包括标签页进程、插件进程和扩展进程等。它可以展示各个进程的资源使用情况,如内存占用、CPU使用率和网络活动等。
进程管理:任务管理器负责启动和关闭浏览器的进程。当用户打开一个新的标签页或启动一个插件时,任务管理器会创建相应的进程。当标签页被关闭或插件停止运行时,任务管理器会结束相应的进程,以释放系统资源。
资源分配:任务管理器根据各个进程的资源需求,动态地分配系统资源。例如,对于需要大量CPU资源的进程,任务管理器会分配更多的CPU时间片。同时,任务管理器还可以确保关键进程(如用户界面进程)始终获得足够的资源,从而保证整个浏览器的流畅运行。
进程隔离:为了提高浏览器的安全性,任务管理器会对各个进程进行隔离。这意味着一个进程无法直接访问另一个进程的内存空间。进程隔离可以防止潜在的安全漏洞影响到整个浏览器系统。
异常处理:任务管理器负责检测和处理进程中的异常情况。当某个进程发生崩溃或无响应时,任务管理器会尝试自动恢复该进程。如果无法恢复,任务管理器会提示用户关闭相应的标签页或插件,以防止整个浏览器崩溃。
浏览器架构分工
思考
为什么会有单进程架构
早期的浏览器中web技术简单,硬件设备也较为落后;此时采用单进程架构易于实现,维护方便,资源消耗较低,兼容性较好。随着技术进步和需求的增加,单进程架构稳定性、安全性和性能方面的问题也逐渐突出,局限性变大导致单进程架构逐渐落伍。
面向服务架构是否会替代多进程架构
面向服务架构可以看作是多进程架构的升级,这种架构将浏览器的各个功能模块化,作为独立的服务来运行和维护,可以更好地管理和维护浏览器的各个功能模块。然而,多进程架构相对简单且易于实现,在很多情况下依旧适合使用。面向服务架构的优势在于模块化和灵活性,它可以根据需求自动扩展或缩减资源。但是,这种架构可能需要更多的系统资源和开发维护成本。多进程架构在资源消耗和开发成本方面可能更具优势。
渲染进程
多进程架构
- 内部是多线程实现,主要负责页面渲染,脚本执行,事件处理,网络请求等
进程与线程
- 进程和线程都是操作系统进行任务管理的基本单位
- 进程:
进程是一个独立的程序执行实例,它包括程序的代码、数据以及运行时所需的系统资源(如文件描述符、内存空间等)。每个进程都有自己的独立地址空间,操作系统会为每个进程分配和管理资源。
进程的特点:
独立性:进程具有独立的地址空间,一个进程无法直接访问另一个进程的资源,除非通过进程间通信(IPC)机制。
隔离性:操作系统会为每个进程分配和管理资源,确保它们之间的隔离。这有助于提高系统的稳定性和安全性。
资源开销:创建和维护进程需要消耗一定的系统资源,如内存、CPU时间等。
应用场景:进程通常用于执行独立的、需要隔离的任务。例如,在多进程浏览器中,每个Tab标签页都运行在一个单独的进程中,以实现进程间的隔离和资源管理。
- 线程:
线程是进程内的一个执行单元,它共享进程的地址空间和资源,但拥有自己的执行堆栈和程序计数器。一个进程可以包含多个线程,它们可以并发地执行任务。
线程的特点:
轻量级:线程比进程更轻量级,创建和切换线程的开销较小。
共享资源:线程之间可以共享进程的地址空间和资源,这使得线程间的通信和数据共享变得更加简单高效。
上下文切换:线程之间的上下文切换成本较低,因为它们共享相同的地址空间。
应用场景:线程通常用于实现并发执行和任务分解。例如,在一个图形编辑器中,可以使用多个线程分别处理用户输入、图形渲染和文件保存等任务,从而提高程序的响应速度和执行效率。
JS引擎 VS 渲染引擎
解析执行JS
JS引擎:JS引擎会将JavaScript源代码解析成抽象语法树(AST),然后通过JIT编译器将AST编译成机器代码,最后执行机器代码。在这个过程中,JS引擎还会进行优化,提高代码的执行效率。常见的JS引擎包括V8(用于Chrome和Node.js)、SpiderMonkey(用于Firefox)和JavaScriptCore(用于Safari)。
渲染引擎:渲染引擎的主要任务是解析HTML和CSS,构建DOM树和渲染树,然后将渲染树转换为屏幕上的像素。在这个过程中,渲染引擎并不直接处理JavaScript代码。然而,当遇到需要执行的JavaScript代码时(例如,通过
<script>标签或事件处理程序),渲染引擎会将控制权交给JS引擎。一旦JS引擎执行完毕,渲染引擎会继续执行后续的渲染任务。
XML解析生成渲染树,显示在屏幕
JS引擎:JS引擎主要处理JavaScript代码,不负责解析XML或生成渲染树。然而,JavaScript可以通过DOM API操作DOM树,从而间接地影响渲染树的生成和更新。
渲染引擎:渲染引擎负责解析HTML和XML文档,构建DOM树。然后,渲染引擎会解析CSS样式,并将样式信息附加到DOM树上,生成渲染树。接下来,渲染引擎会计算每个节点的布局信息(如位置和大小),并将渲染树转换为屏幕上的像素。这个过程被称为“绘制”或“渲染”。
桥接方式通信
JS引擎和渲染引擎之间需要进行通信,以确保JavaScript代码的执行和网页内容的渲染能够协同工作。这种通信通常通过浏览器内部的API和事件机制实现。
JS引擎:JS引擎提供了DOM API,使得JavaScript代码可以访问和操作DOM树。当JavaScript代码需要对DOM树进行操作时(如添加、删除或修改节点),JS引擎会通过浏览器内部的API通知渲染引擎进行相应的
多进程工作流程
- 网络线程负责加载网页资源
网络线程的主要任务是从服务器加载网页资源,如HTML、CSS、JavaScript、图片等。加载过程中,网络线程会将HTML和CSS交给渲染线程进行解析,并将JavaScript交给JS引擎进行解析和执行
- JS引擎解析JS脚本并且执行
JS引擎将接收到的JavaScript代码解析成抽象语法树(AST),然后通过JIT编译器将AST编译成机器代码,最后执行机器代码。在这个过程中,JS引擎还会进行优化,提高代码的执行效率
- JS解析引擎空闲时,渲染线程立即工作
当JS引擎空闲时(即没有JavaScript代码需要执行),渲染线程开始工作。渲染线程负责解析HTML和CSS,构建DOM树和渲染树,计算布局信息,并将渲染树转换为屏幕上的像素。如果在此过程中遇到JavaScript代码(如
<script>标签或事件处理程序),渲染线程会暂停,将控制权交给JS引擎
- 用户交互、定时器操作等产生回调函数放入任务队列中
当用户与网页进行交互(如点击、滚动等),或者有定时器触发(如
setTimeout或setInterval)时,相应的回调函数会被放入任务队列中。任务队列是先进先出(FIFO)的数据结构,用于存储待处理的任务
- 事件线程进行事件循环,将队列里的任务取出交给JS引擎执行
事件线程负责管理事件循环。事件循环的主要任务是检查任务队列,将队列中的任务按顺序取出,并交给JS引擎执行。JS引擎执行任务时,可能会对DOM树进行操作,从而触发渲染线程的更新。事件循环会持续进行,直到任务队列为空,或者浏览器关闭。
思考
// 获取当前时间戳
const now = Date.now();
// 定时器1:10ms后输出"time10"和定时器1的执行延时
setTimeout(() => {
console.log('time10', Date.now() - now); // 输出1:?
}, 10);
// 定时器2:30ms后输出"time30"和定时器2的执行延时
setTimeout(() => {
console.log('time30', Date.now() - now); // 输出2:?
}, 30);
// 一直执行循环,直到距离当前时间戳至少过去20ms
while (true) {
if (Date.now() - now >= 20) {
break;
}
}
// 输出当前已经过去的时间(自now开始计算)
console.log(Date.now() - now); // 输出3:?
这段代码演示了setTimeout的执行顺序以及JavaScript的单线程执行特点
-
输出1:定时器1的回调函数在10ms后加入事件队列。然而,由于
while循环会阻塞主线程,直到至少20ms过去,所以定时器1的回调函数将在while循环结束后立即执行。因此,输出1的值会大于等于20ms,例如:"time10 20"。 -
输出2:定时器2的回调函数在30ms后加入事件队列。因为
while循环在20ms后就结束了,所以定时器2的回调函数会在预期的30ms后执行。因此,输出2的值会接近30ms,例如:"time30 30"。 -
输出3:这个输出表示
while循环结束时已经过去的时间。由于while循环会一直执行,直到至少20ms过去,所以输出3的值会大于等于20ms,例如:"20"。
主要注意的是,由于JavaScript的单线程特性和事件循环机制,setTimeout并不能保证回调函数会在精确的延迟时间后执行。实际的执行时间可能会受到其他任务(如while循环)的影响。
Chrome运行原理
如何展示网页
输入解析:浏览器首先解析输入的内容,判断它是一个有效的URL还是搜索查询。如果输入的内容被识别为搜索查询,浏览器将使用默认的搜索引擎进行搜索。
DNS查询:如果输入的内容是一个有效的URL,浏览器将进行域名系统(DNS)查询以将域名解析为对应的IP地址。浏览器会首先检查本地DNS缓存,如果找不到对应的记录,它会向DNS服务器发送查询请求。
建立连接:浏览器与目标服务器建立一个TCP连接。这通常包括三次握手过程,以确保双方都准备好进行数据传输。
发送HTTP请求:TCP连接建立后,浏览器向服务器发送一个HTTP请求。请求通常包括请求方法(如GET或POST)、请求的资源路径、HTTP协议版本、请求头(包含诸如用户代理、接受的编码和语言等信息)以及可能的请求体(如POST请求所包含的表单数据)。
接收响应:服务器处理HTTP请求,并将响应数据发送回浏览器。响应通常包括HTTP状态码(如200表示成功,404表示未找到等)、响应头(包含诸如内容类型、内容长度等信息)以及响应体(通常是HTML文档)。
关闭或重用连接:一旦浏览器接收到完整的响应数据,它可以选择关闭TCP连接或将其保持在活动状态以用于后续请求。
解析HTML:浏览器解析HTML文档,构建DOM树。在解析过程中,浏览器可能遇到
<script>标签或其他需要立即执行的脚本,这时浏览器将暂停解析,执行脚本,然后继续解析。请求其他资源:HTML文档通常包含其他资源的引用,如CSS、JavaScript和图片等。浏览器将发送额外的HTTP请求来获取这些资源。这些请求可能与初始请求的服务器相同,也可能涉及其他服务器。
构建渲染树:浏览器解析CSS样式,并将其应用于DOM树,生成渲染树。渲染树包含了所有可见元素及其样式信息。
布局:浏览器计算渲染树中每个元素的位置和大小,生成布局信息。
绘制:浏览器根据渲染树和布局信息将元素绘制到屏幕上。这个过程称为绘制或渲染。浏览器会将各个层的元素绘制到位图中,然后将这些位图合成到屏幕上显示的最终图像。
交互:在完成页面绘制后,浏览器开始接收和处理用户的交互,如点击、滚动、输入等。这些交互可能会触发JavaScript事件处理程序,从而修改DOM或应用新的样式。这些修改可能会导致浏览器重新布局和绘制页面的部分或全部内容。
关闭或卸载:当用户导航到其他页面或关闭浏览器选项卡时,浏览器将触发相应的页面卸载事件,如
beforeunload和unload。这给开发者一个机会来执行清理操作,如保存用户数据或取消挂起的网络请求。一旦完成这些操作,浏览器将卸载页面并释放相关资源。
输入处理
-
用户Url框输入内容的后,UI线程会判断输入的是一个URL地址呢,还是一个query查询条件
-
如果是URL,直接请求站点资源
-
如果是query,将输入发送给搜索引擎
开始导航
-
当用户按下回车,UI线程通知网络线程发起一个网络请求,来获取站点内容
-
请求过程中,tab处于loading(转圈等待)状态
读取响应
-
网络线程接收到HTTP响应后,先检查响应头的媒体类型(MIME Type)
-
如果响应主体是一个HTML文件,浏览器将内容交给渲染进程处理
-
如果拿到的是其他类型文件,比如Zip、exe等,则交给下载管理器处理
寻找渲染流程
-
网络线程做完所有检查后,会告知主进程数据已准备完毕,主进程确认后为这个站点寻找一个渲染进程
-
主进程通过IPC消息告知渲染进程去处理本次导航
-
渲染进程开始接收数据并告知主进程自己已开始处理,导航结束,进入文档加载阶段
渲染进程
资源加载
-
收到主进程的消息后,开始加载HTML文档
-
除此之外,还需要加载子资源,比如一些图片,CSS样式文件以及JavaScript脚本
构建渲染树
-
构建DOM树,将HTML文本转化成浏览器能够理解的结构
-
构建CSSOM树,浏览器同样不认识CSS,需要将CSS代码转化为可理解的CSSOM
-
构建渲染树,渲染树是DOM树和CSSOM树的结合
页面布局
-
根据渲染树计算每个节点的位置和大小
-
在浏览器页面区域绘制元素边框
-
遍历渲染树,将元素以盒模型的形式写入文档流
页面绘制
-
构建图层:为特定的节点生成专用图层
-
绘制图层:一个图层分成很多绘制指令,然后将这些指令按顺序组成一个绘制列表,交给合成线程(减少绘制次数)
-
合成线程接收指令生成图块
-
栅格线程将图块进行栅格化
-
展示在屏幕上
前端性能performance
时间都花在哪?
-
页面加载
-
渲染解析
-
js渲染
-
页面绘制
-
...
什么情况下卡顿
卡顿一般是由于浏览器在渲染页面时遇到了阻塞或耗时操作导致的。以下是一些可能导致卡顿的情况:
-
JavaScript执行时间过长:JavaScript的执行会阻塞页面的渲染。如果脚本执行时间过长,会导致页面无响应或卡顿现象。
-
大量的DOM操作:DOM操作会影响页面的渲染,特别是在大量DOM操作时。如果需要频繁地更新DOM元素,可以考虑使用虚拟DOM等技术来减少DOM操作次数。
-
大量的网络请求:浏览器在渲染页面时需要下载和解析HTML、CSS、JavaScript和图像等资源。如果有大量的资源需要下载,会导致页面加载时间过长。
-
大量的样式和布局计算:如果页面包含大量的样式和布局计算,会影响页面的渲染性能。
-
阻塞渲染的JavaScript:如果脚本阻塞了页面的渲染,就会导致卡顿或页面无响应。
首屏优化
- 压缩、分包、删除无用代码
通过压缩代码、分包加载和删除无用代码等技术,可以减小页面的体积,加快页面的加载速度。
- 静态资源分离
将页面中的静态资源(如CSS、JavaScript和图像等)与HTML文档分离,可以使得浏览器可以并行加载这些资源,从而提高页面的加载速度。
- JS脚本非阻塞加载
将JS脚本异步加载,可以减少页面的渲染阻塞,从而提高页面的加载速度。可以使用defer和async等属性来实现JS的非阻塞加载。
- 缓存策略
合理地设置缓存策略,可以减少对服务器的请求,加快页面的加载速度。可以使用HTTP响应头中的Cache-Control和Expires等属性来设置缓存策略。
- SSR
服务器端渲染(Server Side Rendering)可以在服务器端生成HTML文档,减少客户端渲染的工作量,从而提高页面的加载速度。SSR适用于复杂的单页面应用或对SEO有要求的应用。
- 预置loading、骨架屏
在页面加载过程中,可以预置一个loading动画或骨架屏,以提高用户体验。这些技术可以在页面加载完成之前,先显示一些占位元素,给用户一个等待的感觉,从而减少用户等待的焦虑和不安。
渲染优化
- GPU加速
将复杂的图形处理任务交给GPU来处理,可以加快页面的渲染速度。可以使用CSS3的transform和opacity等属性来开启GPU加速。
- 减少回流、重绘
回流和重绘是影响页面性能的主要因素之一。可以通过避免使用影响布局的属性、批量修改DOM元素等技术来减少回流和重绘操作。
- 离屏渲染
离屏渲染是将页面中的部分内容在单独的图层中进行渲染,从而减少对主渲染线程的阻塞。可以使用CSS3的transform和position等属性来开启离屏渲染。
- 懒加载
将页面中的非必要资源(如图片和视频等)延迟加载,可以加快页面的加载速度。可以使用Intersection Observer和Lazyload等技术来实现懒加载。
JS优化
- 防止内存泄漏
有可能出现内存泄漏的场景
全局变量:全局变量会一直存在于内存中,直到程序结束才会被释放。如果程序中定义了大量的全局变量,就会导致内存占用过多,从而导致内存泄漏。
闭包:闭包会在函数中保存局部变量和参数,如果函数执行后,闭包中的变量没有被释放,就会导致内存泄漏。为了避免内存泄漏,应该合理使用闭包,并注意释放不需要的变量。
循环引用:循环引用是指两个或多个对象之间相互引用,形成了一个死循环,导致内存无法释放。为了避免循环引用,应该及时释放不需要的引用,并使用垃圾回收机制来自动释放内存。
定时器和事件监听器:定时器和事件监听器会持续占用内存,直到被清除或被解除绑定。如果程序中存在大量的定时器和事件监听器,就会导致内存占用过多,从而导致内存泄漏。
DOM节点:DOM节点也会占用内存空间,如果程序中存在大量的DOM节点,就会导致内存占用过多,从而导致内存泄漏。为了避免内存泄漏,应该及时清除不需要的DOM节点。
内存泄漏会导致不必要的内存占用和程序崩溃。可以使用let和const关键字声明变量,避免变量污染和内存泄漏。
- 循环尽早break
在循环中,如果已经找到了需要的结果,可以使用break语句尽早结束循环,避免无用的迭代和计算。
- 合理使用闭包
闭包可以在函数中保存局部变量和参数,避免全局变量的污染和泄漏。但是,如果使用不当,也会导致内存泄漏和性能下降。
- 减少Dom访问
DOM操作是JavaScript性能的一个瓶颈。可以使用缓存和批量操作等技术来减少DOM访问次数,从而提高JavaScript的性能。
- 防抖、节流
防抖(debounce): 防抖是指在一定时间内,如果连续触发事件,那么只执行一次目标函数。常用于输入框实时搜索、窗口大小调整等场景。防抖的实现原理是:设置一个定时器,在指定的延迟时间内,如果再次触发事件,则重新计时。只有在延迟时间内没有再次触发事件时,才会执行目标函数。
节流(throttle): 节流是指在一定时间内,无论触发多少次事件,目标函数都只执行一次。常用于滚动事件、鼠标移动等场景。节流的实现原理是:设置一个间隔时间,在这个时间内,无论事件触发多少次,都只执行一次目标函数。一旦超过这个间隔时间,就会再次执行目标函数。
防抖和节流是用来控制函数调用频率的技术。可以使用setTimeout和requestAnimationFrame等API来实现防抖和节流(或者用第三方库也行)。
- Web Workers
Web Workers是一种在后台线程中执行JavaScript代码的技术。可以将耗时的计算任务和数据处理等操作放到Web Workers中执行,避免阻塞主线程,提高页面的响应速度。
跨端容器
WebView
-
Webview,即网页视图,用于加载网页Url,并展示其内容的控件。
-
可以内嵌在移动端App内,实现前端混合开发,大多数混合框架都是基于Webview的二次开发;比如lonic、Cordova。
常用WebView分类
WebView主要优点
-
跨平台兼容性:使用WebView,开发者可以利用Web技术为多个平台(如iOS和Android)创建应用。这可以节省开发时间和成本,一次开发处处使用,学习成本低,同时确保应用在各个平台上提供一致的用户体验。
-
代码重用:WebView允许开发者在移动应用中重用现有的Web代码。这意味着,对于已有Web应用的公司来说,可以更容易地将其产品扩展到移动平台。
-
简化更新过程:随时发布,即时更新,不用下载安装包。WebView使得应用内容的更新变得更加简单。因为WebView直接加载Web内容,开发者可以在服务器端更新应用内容,而无需重新提交整个应用到应用商店进行审核。
-
通过JSBridge和原生系统交互,能够实现一些更加复杂的功能
WebView使用原生能力
- Javascript调用Native
API注入:Native获取]avascript3环境上下文,对其挂载的对象或者方法进行拦截
使用Webview URL Scheme跳转拦截
IOS上window.webkit.messageHandler直接通信
- Native调用Javascript
直接通过webview暴露的API执行JS代码
IOS webview.stringByEvaluatingJavaScriptFromString
Android webview.evaluateJavascript
WebView< - >Nactive 通信
-
JS环境中提供通信的 JSBridge
-
Native端提供 SDK 响应 JSBridge 发出的调用
-
前端和客户端分别实现对应功能模块
实现一个简易的JSBridge
- JSBridge是一种在WebView中实现原生与JavaScript之间通信的技术
小程序
微信、支付宝、百度小程序、小米直达号
渲染层-webview
双线程,多webview架构
数据通信,Native转发
React Native/WeeX
- React Native: React Native是Facebook开发的一个开源框架,它允许开发者使用React和JavaScript编写原生移动应用。
React Native的优势包括:
代码复用:React Native允许开发者在多个平台上复用大部分代码,从而减少开发时间和成本。
热重载:React Native支持热重载功能,允许开发者在不重新编译整个应用的情况下查看代码更改的效果,提高开发效率。
原生性能:虽然React Native使用JavaScript编写,但它将JavaScript代码转换为原生组件,从而提供了接近原生应用的性能。
丰富的生态系统:React Native拥有庞大的社区支持,开发者可以利用许多第三方库和组件来加速开发过程。
- Weex: Weex是由阿里巴巴开发的一个开源框架,它允许开发者使用Vue.js和JavaScript编写原生移动应用。
Weex的优势包括:
代码复用:类似于React Native,Weex也支持在不同平台上复用代码,从而降低开发成本。
原生渲染:Weex将Vue.js组件转换为原生组件进行渲染,从而实现了较高的性能。
插件系统:Weex提供了一个丰富的插件系统,开发者可以使用这些插件来轻松实现原生功能,如地图、支付等。
模块化:Weex允许开发者将应用拆分为多个模块,这有助于实现高度模块化的开发过程,提高代码可维护性。
原生组件渲染
React/Vue框架
virtual dom
JSBridge
Lynx
基于Vue框架
绑定于JS Core / V8
JSBinding
Native UI /Skia
Flutter
Flutter是Google开发的一个开源UI工具包,旨在为开发者提供一种构建优美、高性能的跨平台应用的解决方案。Flutter具有一些独特的特点,包括基于Widget的设计、Dart VM以及使用Skia图形库
wideget
dart vm
skia图形库
通用原理
-
UI组件
-
渲染引擎
-
逻辑控制引擎
-
通信桥梁
-
底层API抹平表面差异
方案对比
思考
- 同样是基于WebView渲染,为什么小程序体验比webview流畅?
小程序相对于WebView,因为平台适配问题,可以对场景进行专门的优化,使得它的体验更佳。
优化的渲染引擎: 小程序的渲染引擎经过针对性优化,以适应移动设备的性能特点。这使得小程序在处理动画、滚动等界面交互时更加流畅。此外,小程序还采用了一些高效的Web渲染技术,如硬件加速、层合成等,从而提高了渲染性能。
分离的逻辑层和渲染层: 小程序将逻辑层(JavaScript代码)和渲染层(UI界面)分开处理。逻辑层运行在Web容器中,而渲染层则运行在一个独立的原生视图中。通过这种分离,小程序可以在不影响UI渲染的情况下执行JavaScript代码,从而提高了应用的流畅度。
限制和优化的API: 小程序提供了一组限制和优化的API,这些API专门针对移动设备的性能和用户体验进行了调整。通过使用这些API,开发者可以更高效地编写适用于移动设备的应用,从而提高应用的流畅度。
资源限制: 小程序对资源的大小和数量有严格的限制,这迫使开发者在设计应用时充分考虑性能优化。较小的资源包意味着更快的加载速度,从而提高了应用的启动速度和运行性能。
预加载和缓存机制: 小程序具有预加载和缓存机制,这使得应用在首次启动时可以快速加载和渲染,从而提高了用户体验。此外,缓存机制还可以减少网络请求和数据传输,降低应用的延迟。
- 未来的跨端方案会是什么
在可见的未来,因为各个公司的存在,跨端方案应该会一直保持着通用+专用的情况。WebView这种通用方案适配更加广泛,标准统一,开发条件低,适合在各种方式下都能使用;但是专用跨端方案,像小程序,因为平台的专有优势可以进行优化,将会在使用场景下表现出更优于通用方案的表现。
总结
客户端容器是前端最重要的展现方式,就像作家手中的稿纸、演员面对的相机,所有的思考和制作表达都要通过它才能传达出来。客户端容器作为前端人吃饭的筷子,我们一定要对它深入了解,明白它的原理,只有真正掌握了它,才能更好的将自己的知识和能力展现出来。