• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Web组件开发性能提升指导
2
3## 简介
4
5开发者实现在应用中跳转显示网页需要分为两个方面:使用@ohos.web.webview提供Web控制能力;使用Web组件提供网页显示的能力。在实际应用中往往由于各种原因导致首次跳转Web网页或Web组件内跳转时出现白屏、卡顿等情况。本文介绍提升Web首页加载与Web网页间跳转速度的几种方法,并提供[示例源码](https://gitee.com/openharmony/applications_app_samples/tree/master/code/Performance/PerformanceLibrary/feature/webPerformance)6
7## 优化思路
8
9用户在使用Web组件显示网页时往往会经历四个阶段:无反馈-->白屏-->网页渲染-->完全展示,系统会在各个阶段内分别进行WebView初始化、建立网络连接、接受数据与渲染页面等操作,如图一所示是WebView的启动阶段。
10
11图一 Web组件显示页面的阶段
12
13![Web组件显示页面的阶段](./figures/web-display-stage.png)
14
15要优化Web组件的首页加载性能,可以从图例标记的三个阶段来进行优化:
16
171. 在WebView的初始化阶段:应用打开WebView的第一步是启动浏览器内核,而这段时间由于WebView还不存在,所有后续的步骤是完全阻塞的。因此可以考虑在应用中预先完成初始化WebView,以及在初始化的同时通过预先加载组件内核、完成网络请求等方法,使得WebView初始化不是完全的阻塞后续步骤,从而减小耗时。
182. 在建立连接阶段:当开发者提前知道访问的网页地址,我们可以预先建立连接,进行DNS预解析。
193. 在接收资源数据阶段:当开发者预先知道用户下一页会点击什么页面的时候,可以合理使用缓存和预加载,将该页面的资源提前下载到缓存中。
20
21综上所述,开发者可以通过方法1和2来提升Web首页加载速度,在应用创建Ability的时候,在OnCreate阶段预先初始化内核。随后在onAppear阶段进行预解析DNS、预连接要加载的首页。
22在网页跳转的场景,开发者也可以通过方法3,在onPageEnd阶段预加载下一个要访问的页面,提升Web网页间的跳转和显示速度,如图二所示。
23
24图二 Web组件的生命周期回调函数
25
26![Web组件的生命周期回调函数](./figures/web-life-cycle.png)
27
28## 优化方法
29
30### 提前初始化内核
31
32当应用首次打开时,默认不会初始化浏览器内核,只有当创建WebView实例的时候,才会开始初始化浏览器内核。
33为了能提前初始化WebView实例,@ohos.web.webview提供了initializeWebEngine方法。该方法实现在Web组件初始化之前,通过接口加载Web引擎的动态库文件,从而提前进行Web组件动态库的加载和Web内核主进程的初始化,最终以提高启动性能,减少白屏时间。
34使用方法如下:
35```javascript
36// ../src/main/ets/pages/WebInitialized.ets
37
38import webview from '@ohos.web.webview';
39
40...
41  aboutToAppear() {
42    // 通过WebviewController可以控制Web组件各种行为。一个WebviewController对象只能控制一个Web组件,且必须在Web组件和WebviewController绑定后,才能调用WebviewController上的方法(静态方法除外)。
43    webview.WebviewController.initializeWebEngine();
44}
45```
46
47### 预解析DNS、预连接
48WebView在onAppear阶段进行预连接socket, 当Web内核真正发起请求的时候会直接复用预连接的socket,如果当前预解析还没完成,真正发起网络请求进行DNS解析的时候也会复用当前正在执行的DNS解析任务。同理即使预连接的socket还没有连接成功,Web内核也会复用当前正在连接中的socket,进而优化资源的加载过程。
49@ohos.web.webview提供了prepareForPageLoad方法实现预连接url,在加载url之前调用此API,对url只进行DNS解析、socket建链操作,并不获取主资源子资源。
50参数:
51
52| 参数名            | 类型      | 说明                                                                                        |
53|----------------|---------|-------------------------------------------------------------------------------------------|
54| url            | string  | 预连接的url。                                                                                  |
55| preconnectable | boolean | 是否进行预连接。如果preconnectable为true,则对url进行dns解析,socket建链预连接;如果preconnectable为false,则不做任何预连接操作。 |
56| numSockets     | number  | 要预连接的socket数。socket数目连接需要大于0,最多允许6个连接。                                                    |
57
58使用方法如下:
59```javascript
60// 开启预连接需要先使用上述方法预加载WebView内核。
61webview.WebviewController.initializeWebEngine();
62// 启动预连接,连接地址为即将打开的网址。
63webview.WebviewController.prepareForPageLoad("https://www.example.com", true, 2);
64```
65
66### 预加载下一页
67开发者可以在onPageEnd阶段进行预加载,当真正去加载下一个页面的时候,如果预加载已经成功,则相当于直接从缓存中加载页面资源,速度更快。一般来说能够准确预测到用户下一步要访问的页面的时候,可以进行预加载将要访问的页面,比如小说下一页, 浏览器在地址栏输入过程中识别到用户将要访问的页面等。
68@ohos.web.webview提供prefetchPage方法实现在预测到将要加载的页面之前调用,提前下载页面所需的资源,包括主资源子资源,但不会执行网页JavaScript代码或呈现网页,以加快加载速度。
69参数:
70
71| 参数名               | 类型               | 说明             |
72|-------------------|------------------|----------------|
73| url               | string           | 预加载的url。       |
74| additionalHeaders | Array<WebHeader> | url的附加HTTP请求头。 |
75
76使用方法如下:
77```javascript
78// ../src/main/ets/pages/WebBrowser.ets
79
80import webview from '@ohos.web.webview';
81...
82
83  controller: webview.WebviewController = new webview.WebviewController();
84    ...
85    Web({ src: 'https://www.example.com', controller: this.controller })
86      .onPageEnd((event) => {
87         ...
88         // 在确定即将跳转的页面时开启预加载
89         this.controller.prefetchPage('https://www.example.com/nextpage');
90      })
91    Button('下一页')
92      .onClick(() => {
93         ...
94         // 跳转下一页
95         this.controller.loadUrl('https://www.example.com/nextpage');
96      })
97```
98
99## 性能分析
100
101### 场景示例
102
103构建通过点击按钮跳转Web网页和在网页内跳转页面的场景,在点击按钮触发跳转事件、Web组件触发OnPageEnd事件处使用Hilog打点记录时间戳。
104
105#### 反例
106
107入口页通过router实现跳转
108```javascript
109// ../src/main/ets/pages/WebUninitialized.ets
110
111...
112Button('进入网页')
113  .onClick(() => {
114    hilog.info(0x0001, "WebPerformance", "UnInitializedWeb");
115    router.pushUrl({ url: 'pages/WebBrowser' });
116  })
117```
118Web页使用Web组件加载指定网页
119```javascript
120// ../src/main/ets/pages/WebBrowser.ets
121
122...
123Web({ src: 'https://www.example.com', controller: this.controller })
124  .domStorageAccess(true)
125  .onPageEnd((event) => {
126     if (event) {
127       hilog.info(0x0001, "WebPerformance", "WebPageOpenEnd");
128     }
129  })
130```
131
132#### 正例
133
134入口页提前进行Web组件的初始化和预连接
135
136```javascript
137// ../src/main/ets/pages/WebInitialized.ets
138
139import webview from '@ohos.web.webview';
140
141...
142Button('进入网页')
143  .onClick(() => {
144     hilog.info(0x0001, "WebPerformance", "InitializedWeb");
145     router.pushUrl({ url: 'pages/WebBrowser' });
146  })
147...
148aboutToAppear() {
149  webview.WebviewController.initializeWebEngine();
150  webview.WebviewController.prepareForPageLoad("https://www.example.com", true, 2);
151}
152```
153Web页加载的同时使用prefetchPage预加载下一页
154```javascript
155// ../src/main/ets/pages/WebBrowser.ets
156
157import webview from '@ohos.web.webview';
158
159...
160  controller: webview.WebviewController = new webview.WebviewController();
161    ...
162    Web({ src: 'https://www.example.com', controller: this.controller })
163      .domStorageAccess(true)
164      .onPageEnd((event) => {
165         if (event) {
166           hilog.info(0x0001, "WebPerformance", "WebPageOpenEnd");
167           this.controller.prefetchPage('https://www.example.com/nextpage');
168         }
169      })
170```
171
172### 数据对比
173
174通过分别抓取正反示例的trace数据后使用SmartPerf Host工具分析可以得出以下结论:
175
176![hilog](./figures/web-hilog.png)
177
178从点击按钮进入Web首页到Web组件触发OnPageEnd事件,表示首页加载完成。对比优化前后时延可以得出,使用提前初始化内核和预解析、预连接可以减少平均100ms左右的加载时间。
179
180![首页完成时延](./figures/web-open-time-chart.png)
181
182从Web首页内点击跳转下一页按钮到Web组件触发OnPageEnd事件,表示页面间跳转完成。对比优化前后时延可以得出,使用预加载下一页方法可以减少平均40~50ms左右的跳转时间。
183
184![跳转完成时延](./figures/web-route-time-chart.png)
185