HarmonyOS鸿蒙Next中优化Web组件实时加载部分url的时间过长问题
HarmonyOS鸿蒙Next中优化Web组件实时加载部分url的时间过长问题
【问题现象】
某些应用如资讯类应用,使用了Web组件来加载相应的云端Html页面。在某些页面内容较大时,页面加载速度较慢,一般需要20s以上,影响用户体验。
【背景知识】
【定位思路】
对于Web组件加载缓慢优化的思路:
- 可以使用预连接、预加载、预获取post请求的能力和预编译生成编译缓存加速Web页面的访问。
- 可以通过模板快载来优化加载速度。
【解决方案】
-
预解析和预连接
可以通过prepareForPageLoad()来预解析或者预连接将要加载的页面,Ability的onCreate中提前初始化Web内核并对首页进行预连接,示例代码如下:
// xxx.ets import { webview } from '[@kit](/user/kit).ArkWeb'; import { AbilityConstant, UIAbility, Want } from '[@kit](/user/kit).AbilityKit'; export default class EntryAbility extends UIAbility { onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { console.log("EntryAbility onCreate"); webview.WebviewController.initializeWebEngine(); // 预连接时,需要將'https://www.example.com'替换成真实要访问的网站地址。 webview.WebviewController.prepareForPageLoad("https://www.example.com/", true, 2); AppStorage.setOrCreate("abilityWant", want); console.log("EntryAbility onCreate done"); } }
-
预加载
能够预测到Web组件将要加载的页面或者即将要跳转的页面。可以通过prefetchPage()来预加载即将要加载页面。预加载会提前下载页面所需的资源,包括主资源子资源,但不会执行网页JavaScript代码。预加载是WebviewController的实例方法,需要一个已经关联好Web组件的WebviewController实例。在下面的示例中,在onPageEnd的时候触发下一个要访问的页面的预加载:
// xxx.ets import { webview } from '[@kit](/user/kit).ArkWeb'; [@Entry](/user/Entry) [@Component](/user/Component) struct WebComponent { webviewController: webview.WebviewController = new webview.WebviewController(); build() { Column() { Web({ src: 'https://www.example.com/', controller: this.webviewController }) .onPageEnd(() => { // 预加载https://www.iana.org/help/example-domains。 this.webviewController.prefetchPage('https://www.iana.org/help/example-domains'); }) } } }
-
预获取post请求
可以通过prefetchResource()预获取将要加载页面中的post请求。在页面加载结束时,可以通过clearPrefetchedResource()清除后续不再使用的预获取资源缓存。以下示例,在Web组件onAppear中,对要加载页面中的post请求进行预获取。在onPageEnd中,可以清除预获取的post请求缓存:
// xxx.ets import { webview } from '[@kit](/user/kit).ArkWeb'; [@Entry](/user/Entry) [@Component](/user/Component) struct WebComponent { webviewController: webview.WebviewController = new webview.WebviewController(); build() { Column() { Web({ src: "https://www.example.com/", controller: this.webviewController }) .onAppear(() => { // 预获取时,需要將"https://www.example1.com/post?e=f&g=h"替换成真实要访问的网站地址。 webview.WebviewController.prefetchResource( {url:"https://www.example1.com/post?e=f&g=h", method:"POST", formData:"a=x&b=y",}, [{headerKey:"c", headerValue:"z",},], "KeyX", 500); }) .onPageEnd(() => { // 清除后续不再使用的预获取资源缓存。 webview.WebviewController.clearPrefetchedResource(["KeyX",]); }) } } }
-
预编译生成编译缓存
可以通过precompileJavaScript()在页面加载前提前生成脚本文件的编译缓存。推荐配合动态组件使用,使用离线的Web组件用于生成字节码缓存,并在适当的时机加载业务用Web组件使用这些字节码缓存。
参考代码如下:
// 载体Ability // EntryAbility.ets import { createNWeb } from "../pages/common" onWindowStageCreate(windowStage:window.WindowStage): void { windowStage.loadContent('pages/Index',(err,data)=>{ // 创建Web动态组件(需传入UIContext),loadContent之后的任意时机均可创建 createNWeb ( "https://www.example.com", windowStage.getMainWindowSync().getUIContext()); if(err.code){ return; } } ); }
// 创建NodeController // common.ets import { UIContext, NodeController, BuilderNode, Size, FrameNode } from '[@kit](/user/kit).ArkUI'; import { webview } from '[@kit](/user/kit).ArkWeb'; // [@Builder](/user/Builder)中为动态组件的具体组件内容 // Data为入参封装类 class Data { url: string = "https://www.example.com"; controller: WebviewController = new webview.WebviewController(); } [@Builder](/user/Builder) function WebBuilder(data: Data) { Column() { Web({ src: data.url, controller: data.controller }) .width("100%") .height("100%") } } let wrap = wrapBuilder<Data[]>(WebBuilder); // 用于控制和反馈对应的NodeContainer上的节点的行为,需要与NodeContainer一起使用 export class myNodeController extends NodeController { private rootnode: BuilderNode<Data[]> | null = null; // 必须要重写的方法,用于构建节点数、返回节点挂载在对应NodeContainer中 // 在对应NodeContainer创建的时候调用、或者通过rebuild方法调用刷新 makeNode(uiContext: UIContext): FrameNode | null { console.log(" uicontext is undefined : " + (uiContext === undefined)); if (this.rootnode != null) { // 返回FrameNode节点 return this.rootnode.getFrameNode(); } // 返回null控制动态组件脱离绑定节点 return null; } // 当布局大小发生变化时进行回调 aboutToResize(size: Size) { console.log("aboutToResize width : " + size.width + " height : " + size.height); } // 当controller对应的NodeContainer在Appear的时候进行回调 aboutToAppear() { console.log("aboutToAppear"); } // 当controller对应的NodeContainer在Disappear的时候进行回调 aboutToDisappear() { console.log("aboutToDisappear"); } // 此函数为自定义函数,可作为初始化函数使用 // 通过UIContext初始化BuilderNode,再通过BuilderNode中的build接口初始化[@Builder](/user/Builder)中的内容 initWeb(url: string, uiContext: UIContext, control: WebviewController) { if (this.rootnode != null) { return; } // 创建节点,需要uiContext this.rootnode = new BuilderNode(uiContext); // 创建动态Web组件 this.rootnode.build(wrap, { url: url, controller: control }); } } // 创建Map保存所需要的NodeController let NodeMap: Map<string, myNodeController | undefined> = new Map(); // 创建Map保存所需要的WebViewController let controllerMap: Map<string, WebviewController | undefined> = new Map(); // 初始化需要UIContext 需在Ability获取 export const createNWeb = (url: string, uiContext: UIContext) => { // 创建NodeController let baseNode = new myNodeController(); let controller = new webview.WebviewController(); // 初始化自定义Web组件 baseNode.initWeb(url, uiContext, controller); controllerMap.set(url, controller) NodeMap.set(url, baseNode); } // 自定义获取NodeController接口 export const getNWeb = (url: string): myNodeController | undefined => { return NodeMap.get(url); }
// 使用NodeController的Page页 // Index.ets import { getNWeb } from "./common" [@Entry](/user/Entry) [@Component](/user/Component) struct Index { build() { Row() { Column() { // NodeContainer用于与NodeController节点绑定,rebuild会触发makeNode // Page页通过NodeContainer接口绑定NodeController,实现动态组件页面显示 NodeContainer(getNWeb("https://www.example.com")) .height("90%") .width("100%") } .width('100%') } .height('100%') } }
注意
后台启动的Web实例不建议超过200个。
更多关于HarmonyOS鸿蒙Next中优化Web组件实时加载部分url的时间过长问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html
更多关于HarmonyOS鸿蒙Next中优化Web组件实时加载部分url的时间过长问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
优化HarmonyOS鸿蒙Next中Web组件实时加载部分URL时间过长问题,可通过以下方式:
-
预解析和预连接:使用
prepareForPageLoad()
在Ability的onCreate
中预解析或预连接页面,提前初始化Web内核。 -
预加载:使用
prefetchPage()
在onPageEnd
时预加载即将访问的页面资源,提前下载主资源及子资源。 -
预获取post请求:使用
prefetchResource()
在页面加载前预获取post请求资源,并在onPageEnd
时清除不再使用的预获取缓存。 -
预编译生成编译缓存:使用
precompileJavaScript()
在页面加载前生成脚本文件的编译缓存,配合动态组件使用,提升加载速度。
后台启动的Web实例不建议超过200个。