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 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 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 177 178从点击按钮进入Web首页到Web组件触发OnPageEnd事件,表示首页加载完成。对比优化前后时延可以得出,使用提前初始化内核和预解析、预连接可以减少平均100ms左右的加载时间。 179 180 181 182从Web首页内点击跳转下一页按钮到Web组件触发OnPageEnd事件,表示页面间跳转完成。对比优化前后时延可以得出,使用预加载下一页方法可以减少平均40~50ms左右的跳转时间。 183 184 185