Applet launch performance (home page launch)

Applets running mechanism

Small program start

There are two types of small program startup:

  • Cold start: The user opens it for the first time, or the user opens it again after the small program is destroyed. In this case, the small program needs to be reloaded and started
  • Hot start: The user has opened a small program, and then opens the small program again within a certain period of time. The small program is not destroyed, but enters the foreground state from the background state

Restart policy

If A small program is started without path (type A scenario), the home page of the small program is displayed by default. Specifying the restartStrategy configuration item in the corresponding JSON file of the page (which can also be configured globally in the window section of app.json) can change this default behavior so that after exiting from A page, the next cold start of A class A scenario can return to the page.

{
  "restartStrategy": "homePage"
}
Copy the code
An optional value meaning
homePage (Default) If you exit the applet from this page, the next applet will be cold launched from the home page
homePageAndLatestPage If you exit the applet from this page, the page will be loaded immediately after the next cold launch with the same parameters (not available for TAB pages).

Startup performance optimization

Code package volume optimization

Fair use subcontracting

Some scenarios in applets (such as advertising pages, active pages, payment pages, etc.) are usually not very complex and relatively independent, and have high requirements on startup performance. Independent subcontracting can operate independently of the main package and other subcontracting. There is no need to download the main package when entering the applet from the standalone package page. Developers are advised to place some of the pages that require high startup performance into a special separate subcontract.

Independent of the subcontract

Independent subcontracting is a special type of subcontracting in small programs that can operate independently of the main package and other subcontracting. There is no need to download the main package when entering the applet from the standalone subcontracting page. The main package is downloaded only when the user enters the normal package or main package page.

Note:

  • Independent subcontracting cannot rely on the contents of the main package and other subcontracting, including JS files, templates, WXSS, custom components, etc
  • App can only be defined in the main package. App cannot be defined in a standalone package, resulting in unexpected behavior
  • Plugins are not currently supported in standalone subcontracting
Subcontract predownload

The use of “subcontracting loading” can significantly improve the startup speed of the small program, but when users jump to the subcontracting page in the process of using the small program, they need to wait for the completion of the subcontracting download before entering the page, resulting in the delay of page switching and affecting the use experience of the small program.The subcontract pre-download is designed to address the delay in first entering the subcontract page.

Note: Excessive pre-download will also break the principle of subcontracting on demand, occupy excessive storage space of users and consume data traffic.

Subcontracting asynchronization

Subcontracting asynchronization refines subcontracting of applets from page granularity to component or even file granularity. This allows components and code logic that would otherwise be placed on pages within the main package to be stripped into subcontracting and loaded asynchronously at run time, further reducing the package size and code required for startup.

Avoid global customization of components and plug-ins
  • If a custom component is only used in a subcontracted page, it should be defined in the configuration file of the page
  • If the plug-in is only used in a subcontract, reference the plug-in only in the subcontract
  • Globally introduced custom components are considered to be required by all subcontracting and all pages, affecting the effect of “injection on demand” and the time it takes to inject small program code.
Reduce the size of resource files in the code package

ZSTD algorithm is used to compress small program code packages during downloading. Resource files such as images, audio, videos and fonts occupy a large volume of code packages and are usually difficult to compress further, which has a much greater impact on download time than code files.

It is recommended that the images in the code package should contain only some small ICONS, and avoid including too many or too large images in the code package or using base64 inline resource files in WXSS. Whenever possible, such files should be deployed to the CDN and imported using urls.

Clean up useless resource code and resources in time

Applet packaging puts all files in the project directory into the code package, except for those ignored by default or explicitly stated by the developer. Accidentally introduced third-party libraries, deprecated code or dependencies during version iterations, test code that is not needed in the production environment, unused components, plug-ins, extension libraries, and other files and resources that are not actually used can also be pushed into the code package and affect the size of the code package.

It is suggested to use the “code static dependency analysis” provided by wechat developer tools to analyze the file composition and dependency relationship of code packages irregularly, so as to optimize the size and content of code packages. For files that are used only for local development debugging and should not be included in the applet code package, you can configure the ignore rule using the packoptions. ignore set by the tool.

When preprocessing small program code using packaging tools such as Webpack, Rollup, etc., you can take advantage of features such as tree-shaking to remove redundant code, and be careful not to introduce unnecessary libraries and dependencies when packaging.

Code injection optimization

Optimized code volume

Use on-demand injection to avoid introducing low-utilization custom components into global declarations.

Optimized execution cost

Use time injection, so that some custom components are not injected at startup, but are injected when they are actually rendered, further reducing the startup and first screen time of small programs.

Optimized first screen rendering

To enable theInitial render cache

As of base library version 2.11.1, applets support enabling initial render caching. After this function is enabled, the view layer does not need to wait for the completion of the initialization of the logical layer when it is not started for the first time, but directly shows the page rendering results to the user in advance, which can greatly advance the time of “home page rendering complete” and the page visible to the user.

Caching request data

Small program provides wx.setStorage, wx.getStorage and other read and write local cache ability, data stored in the local, the return will be faster than the network request. If for some reason the developer is unable to use data prepull and periodic updates, we recommend getting data from the cache first to render the view and waiting for the network request to return to update it.

Skeleton screen

The skeleton screen is usually used to outline the page with some gray blocks before it is completely rendered, and then replaced with real content after the data is loaded.

It is recommended that developers avoid displaying blank pages when the page data is not ready (for example, they need to obtain data from the Internet). Instead, they should display the general structure of the page on the skeleton screen and request data to be returned before updating the page. To improve the user’s waiting intention.

The developer tool provides the ability to generate skeleton screen, which helps developers maintain skeleton screen more easily.

Applets run time performance

Applets running environment

Wechat applets run on a variety of platforms: iOS/iPadOS wechat client, Android wechat client, Windows PC wechat client, Mac wechat client, applets hardware framework and wechat developer tools for debugging, etc.

The script execution environment and the environment used for component rendering are different under different runtime environments, and the performance is also different:

  • On iOS, iPadOS, and Mac OS, the JavaScript code in the applet logic layer runs in JavaScriptCore, and the view layer is rendered by WKWebView, IOS 14, iPad OS 14, Mac OS 11.4, etc.
  • On Android, the JavaScript code of the small program logic layer runs in V8, and the view layer is rendered by the wechat self-developed XWeb engine based on Mobile Chromium kernel.
  • On Windows, the small program logic layer JavaScript and view layer both use Chromium kernel;
  • On the development tool, the JavaScript code of the applet logic layer is run in nw.js and the view layer is rendered by Chromium Webview.

JavaScriptCore cannot enable JIT compilation (just-in-time Compiler), and its performance is significantly lower than that of other platforms under the same conditions.

Platform differences

Although each operating environment is very similar, there are some differences:

  • JavaScriptSyntax and API support inconsistent: syntactically developers can turn it onES6 转 ES5To circumvent (details); In addition, the applets base library has the necessary Polyfill built in to bridge API differences (details).
  • WXSSRender performance is inconsistent: although it can be enabledStyle completionTo avoid most of the problems, it is recommended that developers check the true performance of applets on each side.

Runtime performance optimization

Use setData wisely

SetData process

The process of setData can be roughly divided into several stages:

  • Logical layer virtual DOM tree traversal and update, trigger component life cycle and observer, etc.
  • Transfer data from the logical layer to the view layer
  • The view layer updates the virtual DOM tree, updates the real DOM elements, and triggers page rendering updates.
Data communication

For step 2, because of the small program logic layer and view layer are two independent running environment, belong to a different thread, or process, not directly for data sharing, the need for data serialization, cross thread/process data transmission, data deserialization, so the process is asynchronous, non real-time data transmission.

On iOS/iPadOS/MacOS, the data transfer is implemented through evaluateJavascript, with additional JS script parsing and execution time.

The data transfer time is positively related to the data volume. If the peer thread is busy, the data will be waiting in the message queue.

Use advice
  • ✅ The data field of a page or component to store data related to page or component rendering (that is, fields that appear directly in WXML);
  • Data indirectly associated with ✅ pages or component renderers can be set as “pure data fields,” which can be set using setData and observers for changes using observers;
  • ✅ page or component rendering irrelevant data should be hung under non-data fields, such asthis.userData = {userId: 'xxx'};
  • ✅ setData should only pass in fields that have changed;
  • ✅ Suggest using [Data path]
  • ✅ page after the background update operation, should be avoided as far as possible, or delayed to the pageonShowPostponement;
  • ✅ For page elements that need to be updated frequently (for example, seconds countdown), you can encapsulate them as separate components within which you can perform setData operations. If necessary, you can use the CSS contain property to limit how much layout, styling, and drawing can be computed.
  • ✅ call setData only when page content needs to be updated;
  • ✅ merge successive setData calls as much as possible;
  • ❌ Avoid including render irrelevant business data in data;
  • ❌ Avoid using data to share data between pages or component methods;
  • ❌ avoid abusing pure data fields to hold data that could be saved using non-data fields.
  • ❌ Avoid unnecessary setData;
  • ❌ Avoid continuous calls to setData at too high a frequency, such as a millisecond countdown;
  • ❌ avoid calling setData every time in the onPageScroll callback.

(developers.weixin.qq.com/miniprogram… ‘:’ newVal ‘, ‘A.B.C.D’ : ‘newVal’}) `, rather than each time the entire object or array;

  • ❌ Don’t be lazy in setData and pass all data at once:this.setData(this.data).
  • ❌ Avoid high-frequency setData, such as countdown updates, after background cutting.

Page switching optimization

Avoid time-consuming operations at onHide/onUnload

When a page switches, the onHide or onUnload life cycle of the previous page is called before the new page is created and rendered. If onHide and onUnload take too long, they can cause delays in page switching.

  • The logic in ✅ onHide/onUnload should be as simple as possible. If you must do some complex logic, you can consider using setTimeout delay.
  • ❌ Reduces or avoids time-consuming logic such as synchronous interface calls and setData in onHide/onUnload.
Initiate data requests in advance

In high-performance scenarios, when using JSAPI for page hops (such as Wx.Navigateto), you can do some preparatory work for the next page. Pages can communicate with each other through EventChannel.

For example, when a page jumps, data requests for the next page can be initiated at the same time, instead of waiting for the page onLoad, so that users can see the page content earlier. Especially when jumping to a subcontracted page, there may be a long time interval between the origination page and the page onLoad to take advantage of.

Rendering performance optimization

Listen for scroll events on a page or component as appropriate

Whenever the user passes in an onPageScroll listener during Page construction, the base library assumes that the developer needs to listen for the Page SCOLl event. At this point, when the user slides the page, events are sent from the view layer to the logical layer at a high frequency, resulting in certain communication overhead.

Similarly, this applies to < scrollview >, and other components that can listen for sliding events using BindScroll.

Because the scroll event is triggered with a high frequency, it is easy for developers to misuse it. Note when using it:

  • ✅ Do not listen for scroll events unnecessarily;
  • ✅ when implementing scroll-related animations, priority is given to scroll-driven animations (

    only) or WXS response events
  • When ❌ does not need to listen for events, the Page should be constructed without passing in the onPageScroll function, rather than leaving the function blank;
  • ❌ Avoid executing complex logic in scroll event listeners;
  • ❌ Avoid frequent calls to setData or the synchronization API in scroll event listeners.
Page({onPageScroll () {} // ❌ do not leave empty function}) Page({// ✅ should not be passed directly})Copy the code
Choose a high performance animation implementation

Developers should choose high performance animation implementation when developing interface animation.

  • ✅ Prioritize animations using CSS gradients, CSS animations, or any other animation implementation provided by the applets framework;
  • ✅ In some complex scenes, if the above methods cannot be met, WXS response events can be used to dynamically adjust the style attribute of nodes to achieve animation effects. At the same time, this method can also be based on the user’s touch events to dynamically generate animation;
  • ❌ avoid animation by changing the form of the interface through successive setData. Although the implementation is simple and flexible, it is easy to have a large delay or lag, and even lead to the death of small programs.
  • ✅ If you have to use setData, try to change the setData in the page to setData in the custom component to improve performance.
IntersectionObserver is used to monitor element exposure

Some business scenarios may require monitoring element exposure for changes in page state or for reporting analysis.

  • ✅ suggests that intersecting states of node layout be monitored by IntersectionObserver to infer whether certain nodes are visible and what proportion of them are visible.
  • ❌ avoids listening for the onPageScroll event and determines whether an element is visible in a callback by continuously querying node information SelectQuery.
Controls the amount of custom data passed in during Page construction

For ease of development, developers can add any function or data to the Object argument passed in the Page construct and access it within the Page function using this. Such as:

Page({data: {} userInfo: {} // Custom data currentUser: OnTap () {} onLoad() {console.log(this.currentUser)}})Copy the code

To ensure that custom data is a different instance in different page instances, the applets framework makes a deep copy of this data (except for function-type fields) at page creation time, which can be expensive if the custom data is too much or too complex.

  • ✅ For more complex data objects, it is recommended that thePage onLoad 或 Component createdIs manually assigned to this instead of being passed in as an argument when the Page is constructed.
// ❌ use complex objects as custom data Page({onLoad() {} bigData: {/* A complex object */}, longList: [/* A long complex array*/]}) // ✅ runtime manual assignment to this. Developers can choose to make deep copy, shallow copy, or no copy as required. Page({ onLoad() { this.bigData = { /* A complex object */ }, this.longList = [ /* A long complex array*/ ] } })Copy the code

Resource loading optimization

Controls the size of the image resource

The developer should choose the appropriate image size, image format, and compression ratio based on the functional requirements and actual display area size.

Too large a picture may have the following consequences

  • Increase the image download time, resulting in the user to see the image time delay;
  • Unnecessary traffic consumption to users;
  • It will affect the time consuming of image decoding and drawing, and may be more likely to cause frame drop, lag or blank screen, and even unable to scroll and switch pages normally (especially on low-end devices);
  • Memory usage increases, especially large images and large numbers of images in long lists, can cause memory usage to rise dramatically.

Image impact on memory

The iOS system reclaims some WebViews when memory is insufficient. Large pictures and a large number of pictures in a long list are easy to cause the system to recycle WebView, resulting in a blank screen for small programs. In serious cases, wechat will be triggered to forcibly close small programs.

If the memory growth exceeds the limit, the small program will have a white screen or a black screen, or even the entire small program will blink back.

Avoid abusing the image component’s widthFix/heightFix mode

WidthFix /heightFix dynamically changes the height or width of an image after it has been loaded. Dynamic changes in image height or width can cause extensive layout rearrangement within the page, resulting in page jitter and stutter.

For the background image or banner image of the page, the size of the image should be specified in advance as far as possible to avoid the secondary size adjustment after the image is loaded.

Memory optimization