跃迁引擎

空気を読んだ雨降らないでよ

iOS Research & Development


HarmonyOS - Web 运行流程原理解析

Web渲染流程

初始化 webview -> 请求页面 -> 下载数据 -> 解析HTML -> 请求 js/css 资源 -> dom 渲染 -> 解析 JS 执行 -> JS 请求数据 -> 解析渲染 -> 下载渲染图片

img

  1. 初始化 WebView

操作:创建并初始化一个WebView组件。

目的:为后续加载和渲染网页提供容器。

细节:

初始化过程中,可以设置各种配置选项,如缓存策略、用户代理、JavaScript执行权限等。

  1. 请求页面

操作:向WebView发送一个请求,加载指定的URL。

目的:启动页面加载过程。

细节:

创建一个URL对象,并使用它构造一个请求对象。

将请求对象传递给WebView,触发页面加载。

可以设置各种监听器来监控加载进度和结果。

  1. 下载数据

操作:WebView开始下载页面数据。

目的:获取页面的主要HTML内容和其他相关资源。

细节:

WebView会向服务器发起HTTP请求,下载页面的主要HTML文件。

下载过程中,WebView会处理各种网络请求,包括重定向、认证等。

下载的数据会暂时存储在内存中,等待进一步处理。

  1. 解析 HTML

操作:解析下载的HTML数据,构建DOM树。

目的:将HTML文本转换成DOM树结构。

细节:

解析器逐行读取HTML文本,并根据HTML语法构建DOM节点。

构建的DOM树包含了页面的所有元素及其属性。

解析过程中,可能会发现外部资源(如CSS、JavaScript文件),并发起相应的请求。

  1. 请求 JS/CSS 资源

操作:根据DOM树中的引用,请求外部的JavaScript和CSS资源。

目的:下载页面所需的样式和脚本文件。

细节:

遍历DOM树中的<link><script> 标签,提取出外部资源的URL。

发起HTTP请求,下载这些资源。

下载的资源会暂时存储在内存中,等待进一步处理。

  1. DOM 渲染

操作:基于DOM树和下载的CSS资源,生成可视化页面。

目的:将DOM树转换成可视化的页面布局。

细节:

根据DOM树和CSS规则计算每个元素的位置和尺寸。

生成渲染树(Render Tree),包含每个元素的视觉表现。

将渲染树绘制到屏幕上,显示初步的页面内容。

  1. 解析 JS 并执行

操作:解析并执行页面中的JavaScript代码。

目的:执行页面中的脚本逻辑,动态修改DOM树。

细节:

解析器逐行读取JavaScript代码,并执行相应的函数和操作。

JavaScript代码可以修改DOM树,添加或删除元素,绑定事件处理程序等。

执行过程中,可能会发起新的网络请求。

  1. JS 请求数据

操作:JavaScript代码发起新的网络请求,获取动态数据。

目的:加载动态数据并更新页面内容。

细节:

JavaScript代码使用AJAX或其他网络请求库发起请求。

请求的数据可能包括JSON、XML等格式。

数据返回后,JavaScript代码会更新DOM树,重新渲染页面。

  1. 解析渲染

操作:根据更新后的DOM树重新渲染页面。

目的:显示更新后的页面内容。

细节:

重新计算DOM树的布局和样式。

更新渲染树,并重新绘制到屏幕上。

显示更新后的页面内容。

  1. 下载渲染图片

操作:下载页面中的图片资源,并将其渲染到页面中。

目的:加载并显示页面中的图片。

细节:

根据DOM树中的标签,发起图片资源的下载请求。

下载的图片会存储在内存中,并插入到DOM树对应的元素中。

图片加载完成后,重新渲染页面,显示图片内容。

Web组件的生命周期

开发者可以使用Web组件加载本地或者在线网页。

Web组件提供了丰富的组件生命周期回调接口,通过这些回调接口,开发者可以感知Web组件的生命周期状态变化,进行相关的业务处理。

Web组件的状态主要包括:Controller绑定到Web组件、网页加载开始、网页加载进度、网页加载结束、页面即将可见等。

图1 Web组件网页正常加载过程中的回调事件

img

Web组件网页加载的状态说明

aboutToAppear函数

在创建自定义组件的新实例后,在执行其build函数前执行。一般建议在此设置WebDebug调试模式setWebDebuggingAccess、设置Web内核自定义协议URL的跨域请求与fetch请求的权限customizeSchemes、设置CookieconfigCookie等。

aboutToAppear函数在创建自定义组件的新实例后,在执行其build()函数之前执行。允许在aboutToAppear函数中改变状态变量,更改将在后续执行build()函数中生效。实现自定义布局的自定义组件的aboutToAppear生命周期在布局过程中触发。

onControllerAttached事件

当Controller成功绑定到Web组件时触发该回调,推荐在此事件中注入JS对象registerJavaScriptProxy、设置自定义用户代理setCustomUserAgent,可以在回调中使用loadUrl,getWebId等操作网页不相关的接口。但因该回调调用时网页还未加载,因此无法在回调中使用有关操作网页的接口,例如zoomIn、zoomOut等。

onLoadIntercept事件

当Web组件加载url之前触发该回调,用于判断是否阻止此次访问。默认允许加载。

onOverrideUrlLoading事件

当URL将要加载到当前Web中时,让宿主应用程序有机会获得控制权,回调函数返回true将导致当前Web中止加载URL,而返回false则会导致Web继续照常加载URL。onLoadIntercept接口和onOverrideUrlLoading接口行为不一致,触发时机也不同,所以在应用场景上存在一定区别。主要是在LoadUrl和iframe(HTML标签,表示HTML内联框架元素,用于将另一个页面嵌入到当前页面中)加载时,onLoadIntercept事件会正常回调到,但onOverrideUrlLoading事件在LoadUrl加载时不会触发,在iframe加载HTTP(s)协议或about:blank时也不会触发。详细介绍请见onLoadIntercept和onOverrideUrlLoading的说明。

  • onLoadIntercept事件:当Web组件加载url之前触发该回调,用于判断是否阻止此次访问。默认允许加载。
  • onOverrideUrlLoading事件:
    • 当URL将要加载到当前Web中时,让宿主应用程序有机会获得控制权,回调函数返回true将导致当前Web中止加载URL,而返回false则会导致Web继续照常加载URL。
    • POST请求不会触发该回调。
    • iframe加载HTTP(s)协议或about:blank时不会触发该回调,加载非HTTP(s)协议的跳转可以触发。调用loadUrl(String)主动触发的跳转不会触发该回调。
    • 不要使用相同的URL调用loadUrl(String)方法,然后返回true。这样做会不必要地取消当前的加载并重新使用相同的URL开始新的加载。继续加载给定URL的正确方式是直接返回false,而不是调用loadUrl(String)。

onInterceptRequest事件

当Web组件加载url之前触发该回调,用于拦截url并返回响应数据。

onPageBegin事件

网页开始加载时触发该回调,且只在主frame(表示一个HTML元素,用于展示HTML页面的HTML元素)触发。如果是iframe或者frameset(用于包含frame的HTML标签)的内容加载时则不会触发此回调。多frame页面有可能同时开始加载,即使主frame已经加载结束,子frame也有可能才开始或者继续加载中。同一页面导航(片段、历史状态等)或者在提交前失败、被取消的导航等也不会触发该回调。

onProgressChange事件

告知开发者当前页面加载的进度。多frame页面或者子frame有可能还在继续加载而主frame可能已经加载结束,所以在onPageEnd事件后依然有可能收到该事件。

onPageEnd事件

网页加载完成时触发该回调,且只在主frame触发。多frame页面有可能同时开始加载,即使主frame已经加载结束,子frame也有可能才开始或者继续加载中。同一页面导航(片段、历史状态等)或者在提交前失败、被取消的导航等也不会触发该回调。推荐在此回调中执行JavaScript脚本loadUrl等。需要注意的是收到该回调并不能保证Web绘制的下一帧将反映此时DOM的状态。

onPageVisible事件

当HTTP响应的主体开始加载,新页面即将可见时触发该回调,且只在主frame触发。此回调在文档加载的早期触发,因此链接的资源比如在线CSS、在线图片等可能尚不可用。

onRenderExited事件

应用渲染进程异常退出时触发该回调, 可以在此回调中进行系统资源的释放、数据的保存等操作。如果应用希望异常恢复,需要调用loadUrl接口重新加载页面。

onDisAppear事件

组件卸载消失时触发此回调。该事件为通用事件,指组件从组件树上卸载时触发的事件。

Web组件网页加载的性能指标

网页加载过程中需要关注一些重要的性能指标。例如,FCP(First Contentful Paint)首次内容绘制,FMP(First Meaningful Paint)首次有效绘制,LCP(Largest Contentful Paint)最大内容绘制等。Web组件提供了如下接口来通知开发者。

onFirstContentfulPaint事件

网页首次内容绘制的回调函数。首次绘制文本、图像、非空白Canvva或者SVG的时间点。

onFirstMeaningfulPaint事件

网页首次有效绘制的回调函数。首次绘制页面主要内容的时间点。

onLargestContentfulPaint事件

网页绘制页面最大内容的回调函数。可视区域内容最大的可见元素开始出现在页面上的时间点。

最近的文章

HarmonyOS - Event Loop事件循环、宏任务and微任务

在阅读本文前先给大家抛出几个问题: 事件循环是什么? 宏任务和微任务是什么? 哪些代码触发宏任务,哪些代码触发微任务? 前言JS是一门单线程语言,单线程就意味着,所有的任务需要排队,前一个任务结束,才会执行下一个任务。 这样所导致的问题是:如果JS执行的时间过长,这样就会造成页面的渲染不连贯 …

, , , 开始阅读
更早的文章

Rust - 基于 FFI 的移动端跨平台 SDK 的探索和实践

为什么要跨平台 减少人力成本,减少开发时间。 抹平多端在逻辑细节的实现差异,提高代码一致性,保证工程质量。 多个平台共享一套代码,后期产品维护简单。 目前常见的跨平台方案C++很多公司的跨平台移动基础库基本都有 C++ 的影子,如微信,腾讯会议,还有早期的 Dropbox,知名的开源库如微信 …

, , 开始阅读
comments powered by Disqus