Project Brief & questions

First a brief introduction to the project, is a more conventional ordering small procedures.

The interface is shown as follows:

The left side is the classification menu, the right side is the long list, there are multiple categories of goods, a single category after scrolling can continue to switch to the next category, at the same time, the left category menu selection will switch to the current list of goods displayed in the category.

For better user experience, and with reference to meituan and other small ordering programs, the data for this list is returned once. The problem is that when there are a lot of items, the first render takes a long time and the page gets stuck.

To optimize the direction

Logic optimization

Whisper BB: Actually the original code (due to historical reasons) was poorly written… OTL

Let’s start with a picture 👇

Small voice BB: even small procedures can not see, to warn o(╯□╰)o

Wechat developer tools have a warning, and there is also a prompt to locate the location of the specific code, so the key is this setData!!

We can start by looking at some of the official recommendations for applets performance and setData optimization. (developers.weixin.qq.com/miniprogram…).

Specific practice:

1. setDataDo not pass too much data at once, if the list is too long, it can be rendered separately (e.g. to a two-dimensional array, one array at a time).

V1: Rough and easy version

// Render one category at a time
// Suppose goodsList is a two-dimensional array
goodsList.forEach((item, index) = > {
    this.setData({
        [`goodsList[${index}] `]: item
    })
})
Copy the code

There is a problem when you write like the above. The first screen rendering of the page is fast, but when you click the page operation (such as the “add” button), the page will get stuck and the reaction will come back after a while. The operation feedback delay is serious.

In fact this is because, the cycle is to reduce the number of single setData, but turned into a circular setData for many times, we look at the first screen, but other classification (array) other rendering, thread or busy, JS thread has been compiled to perform rendering, click event is not passed to the logic layer in time, The logical layer is also unable to deliver the results of the operation to the view layer in a timely manner.

V2: Timer hack version

Since the JS thread is busy rendering, we can force it to stop first. Hence v2’s timer hack.

// Render one category at a time
let len = data.goodsList ? data.goodsList.length : 0;
let idx = 0
let timer = setInterval(() = > {
    if (idx < len) {
        that.setData({
            [`goodsList[${idx}] `]: data.goodsList[idx]
        });
        idx++
    } else {
        clearInterval(timer)
    }
}, 15);
Copy the code

The first screen rendering speed has been fixed, and the button delay response has been fixed. It’s code that’s a bit of a hack

V3: Killer – virtual list

Virtual list simply principle is only to render the current display screen area and n screen before and after n panel data, using a single field to save the current need to display the array (that is, before the current screen + n + n screen after screen), each time a scrolling list to recalculate the need to display the data, update the fields, the page will be updated accordingly. This ensures that the number of element nodes on the page is not too high, which can support long lists with large amounts of data.

More detailed principles and implementation of the students can be searched, not expanded here.

The miniprogram also has an open source virtual list component: Recycle-View

2. setDataGranular updates can be supported, specifying specific attributes.

For example, to add a purchase, you need to update the small number in the upper right corner of the product, you can write:

this.setData({
    [`goodsList[${categoryIndex}] [${goodsIndex}].num`]: goodsItem.num
})
Copy the code

3. Do not save data that is not relevant to the pagedata, do not usesetDataUpdate, becausesetDataTriggers page rendering.

Eg:

Page({
    data: {... },// Data not related to page rendering
    state: {
        hasLogin: false,},... })// Assign the value directly when updating
this.state.hasLogin = true
Copy the code

PS: or you don’t even need to mount it to the page object, just save it as a normal variable.

4. Image size optimization

If the size of images in a long list is not limited, a large number of large images will occupy a lot of memory, which may lead to an increase in the memory usage of iOS clients and trigger the system to reclaim the applet page. In addition to memory problems, large images can cause page-switching delays.

The solution is to take an image of the right size (2x – 3x) depending on the size of the image area currently displayed.

It is recommended to use CDN for pictures. Generally, CDN service providers that provide picture services provide an interface for cutting pictures. Then, the interface only returns the link of the original picture, and the front end transmits parameters to cut pictures as required. The front-end can write common image processing methods, or encapsulate the image components themselves.

CDN service provider picture clipping API document:

  • Ali cloud OSS picture zoom
  • Seven niuyun image processing

5. Reduce unnecessary data requests

For example, when entering the ordering page, the location needs to be obtained, and then the nearest store needs to be obtained according to the location. The first two interfaces need to be requested (specific requirements can be based on business requirements), and if the nearest store obtained is the same as last time, store details and commodity data need not be obtained again.

Experience optimization

1. Merge multiple loading hints within a short period of time

Or the ordering page process, as mentioned above, when entering the page, you need to obtain the positioning interface, and then take the positioning value to obtain the nearest store after the positioning interface returns the result, and finally request the store and commodity data.

These three interfaces are serial. If a loading prompt is displayed for each interface, loading will appear for a while, then disappear, then display for a while, then disappear again… This phenomenon, this experience is not very good.

It is recommended that you encapsulate the request and process loading uniformly in the request to combine the loading that initiates multiple requests within a short period of time.

Eg:

let showLoadingTimer = null;
let showRequestLoading = false; // Flags whether loading is being displayed

/** * encapsulates request *@param {*} {showLoading: Whether loading, options: request parameters, such as URL, data, etc.} * /
function request({showLoading = true. options}) {
    // Display request loading
    handleShowLoading(showLoading)

    wx.request({
        ...
        complete() {
            // Disable request loading
            handleShowLoading(false)}}}/** * Encapsulates request loading * If showLoading is called multiple times in a short period of time, it will be displayed together instead of flashing each one *@param showLoading* /
function handleShowLoading(showLoading) {
    if (showLoading) {
        / / display loading
        clearTimeout(showLoadingTimer);
        if(! showRequestLoading) { showRequestLoading =true;
            wx.showNavigationBarLoading();
            wx.showLoading({ title: "Loading".mask: true}}})else {
        // Disable loading after 200ms
        showLoadingTimer = setTimeout(() = > {
            showRequestLoading = false;
            wx.hideNavigationBarLoading();
            wx.hideLoading()
        }, 200)}}Copy the code

2. When loading the whole page for the first time, you can use page loading animation or skeleton screen to optimize the loading experience.

3. Silently obtain and update data

For example, the onShow of this ordering page calls the location interface and the nearest store interface every time, but the loading is not displayed, so the user has no perception and has a good experience.

Interface optimization

Focus on granularity control of interfaces. Because interfaces are sometimes merged, the front end can save one request for a better experience; However, sometimes if the interface is too much data and too slow to respond, you can consider whether some of the data can be retrieved later, so that the main page content is rendered first, and split the interface according to this design.

For example, in the ordering page of the project, the original shopping cart data and the detailed data displayed in the popup window of commodity specifications are all returned at one time from the commodity interface of the store. However, this interface is designed to return all commodities at one time, which will cause too much data, and the back-end needs to query more tables. By separating the get shopping cart interface and the item details interface into separate interfaces, the response time for the get store item interface is reduced and the page is displayed faster.

conclusion

In fact, many of the logic optimization and interface optimization mentioned above are details, not too advanced technology, we can pay attention to the usual iteration. The optimization of experience requires front-end students to pay more attention to user experience and design knowledge in addition to front-end technology, and this is also a skill that an ambitious front-end should have… Please _ please

So…… The technology road is long, let’s encourage each other

Refer to the article

Developers.weixin.qq.com/miniprogram…