How EdgeScript works
Different from traditional H5 applications, the applet running architecture is divided into two parts: webview and worker. The webview is responsible for rendering, and the worker is responsible for storing data and executing business logic.
The communication between the webview and the worker is asynchronous. This means that when we call setData, our data is not rendered immediately, but needs to be transferred asynchronously from the worker to the webview.
When Data Transmission Service, it needs to be serialized as a string and then transmitted in evaluateJavascript way. The data size will affect the performance.
Optimize the first screen
The first screen has multiple definitions. Here, the first screen refers to the first meaningful rendering from a business perspective. For example, for a list page, the first screen is the first rendered content of the list.
Control applet resource package size
When a user accesses an applet, the client first downloads the applet resource package from the Alibaba Cloud Content Delivery Network, so the size of the resource package affects the startup performance of the applet.
Optimization suggestions
Delete useless image resources in a timely manner, because all image resources are packaged by default.
Control the image size and avoid using large images. We recommend that you upload large images from Alibaba Cloud Content Delivery Network channels.
Clean up useless code in a timely manner.
Advance data requests to onLoad
When the applet runs, the onLoad lifecycle function of the page is triggered first, and then the page initial data (Page data) is passed from the worker to the webview for an initial rendering.
The initial rendering of the page is complete and a notification is sent from the webview to the worker, triggering the onReady lifecycle function.
Some mini programs send requests in onReady, which delays the rendering of the first screen. We recommend that you advance data requests to onLoad.
Control the number of one-time rendering nodes on the first screen
After the service request is returned, setData is usually called to trigger page re-rendering. The execution process is as follows:
Data is passed from the worker to the webview.
The virtual DOM is constructed on the webview based on the passed data, compared with the previous differences (starting from the root node), and then rendered.
When the worker communicates with the webview, the data needs to be serialized and then the webview needs to execute the evaluateJavascript. Therefore, if the data transmitted at one time is too large, the rendering performance of the first screen will be affected.
In addition, if there are too many construction nodes and the hierarchy nesting is too deep on the webview, for example, some small program list pages render more than 100 list items at one time, and each list item has nested content, but in fact the whole screen may only display less than 10, which will lead to a long difference comparison time. At the same time, due to the first screen rendering, many DOM will be constructed at one time, affecting the first screen rendering performance.
Optimization suggestions
The amount of setData data should not be too large to avoid passing an excessively long list at a time.
Do not construct too many nodes at one time on the first screen. The server may request to transfer a large amount of data at one time. Do not setData at one time. You can setData part of the data first, and then wait for a period of time (such as 400ms, which requires service adjustment) before calling $spliceData to pass the other Data Transmission Service.
Optimize the setData logic
Any page change will trigger setData, and multiple setData may trigger the page to re-render at the same time. The following four interfaces will trigger the webview page to re-render.
Page.prototype.setData: Trigger the entire page to do difference comparison.
Page.prototype.$spliceData: Optimized for long lists to avoid passing the entire list each time and triggering the entire page for difference comparison.
Component.prototype.setData: Differences are compared only from the corresponding component node.
Component.prototype.$spliceData: Optimized for long lists to avoid passing the entire list each time, only starting from the corresponding component node for difference comparison.
Optimization suggestions
Avoid frequently triggering setData or $spliceData, regardless of page level or component level. In the cases we analyzed, some pages have countdown logic, but some countdown triggers too frequently (ms-level triggers).
If you need to frequently trigger re-rendering, do not use setData and $spliceData at the page level, encapsulate this block into a custom component, and then use setData or $spliceData at the component level to trigger the re-rendering of the component.
When a long list of data triggers rendering, use $spliceData to append the data multiple times without passing the entire list.
We recommend that you encapsulate complex pages into custom components to reduce setData at the page level.
Optimization cases
Set data recommend the specified path:
this.setData({
'array[0]': 1,
'obj.x':2,
});The following usage is not recommend (although this.data is copied, its attributes are directly changed):
const array = this.data.array.concat();
array[0] = 1;
const obj={...this.data.obj};
obj.x=2;
this.setData({array,obj});It is not recommend to directly change this.data (violating the principle of immutable data):
this.data.array[0]=1;
this.data.obj.x=2;
this.setData(this.data)Long lists use $spliceData:
this.$spliceData({ 'a.b': [1, 0, 5, 6] })Usage notes
Sometimes the business logic is encapsulated in a component. When the component UI needs to be re-rendered, you only need to call setData inside the component. However, sometimes you need to trigger component re-rendering from the page. For example, the onPageScroll event is listened to on the page. When the event is triggered, you need to notify the corresponding component to re-render. In this case, the following action is taken:
// pages/index/index.js
Page({
onPageScroll(e) {
if (this.xxcomponent) {
this.xxcomponent.setData({
scrollTop: e.scrollTop
})
}
}
})// components/index/index.js
Component({
didMount(){
this.$page.xxcomponent = this;
}
})You can mount a component to the corresponding page in the didMount of the component. You can call setData at the component level on the page to only trigger the re-rendering of the component.
Use the key parameter
Use keys in for to improve performance.
The key cannot be set on a block.
Sample code:
<view a:for="{{array}}" key="{{item.id}}"></view>
<block a:for="{{array}}"><view key="{{item.id}}"></view></block>