Recently has been tossing mpVue write micro channel small program performance optimization, share the actual combat process.

Before and after optimization:

813KB
387KB
B
A
Small program running in the process of the sense of lag

General optimization

The usual Web side optimization methods are also applicable in small programs, and should not be ignored.

First, compress the picture

This step is the easiest, but often overlooked. Compress online on Tiny, then download and replace.

72%
813KB
387KB

Remove useless libraries

I used Vant downloadp in my previous projects, adding the entire library under the static directory, but I only used a few components, such as button,field,dialog, etc., which was unnecessary.

So simply remove, wechat small program itself provided button, Wx. ShowModal and other components can basically meet the needs, their handwriting style does not take any time.

Here we suggest that in wechat small programs, try to avoid using too many dependent libraries.

Do not covet convenience and the introduction of some larger library, small procedures are different from the Web, more restrictions, can write their own try to write it.

Optimization of small programs

We first have to look at the official optimization recommendations, mostly around this recommendation to do.

Vue. Config. _mpTrace = true

This is a black technology of MPvue performance optimization ah, probably most students do not know this, I did not find this configuration in the official document, I am really convinced.

/ SRC /main.js add Vue. Config. _mpTrace = true, for example:

Vue.config._mpTrace = true
Vue.config.productionTip = false
App.mpType = 'app'
Copy the code

Added the vue.config. _mpTrace property so that you can see that the console prints the amount of data updated every 500ms. As shown in figure:

If the data update volume is very large, it will be obvious that the small program running card, on the contrary, smooth

2. Simplify data

1. Filter the redundant data returned by the API

Back-end API may need to provide services for iOS, Android, H5, etc., often some redundant data applet is not used. For example, an API returns a list of articles with many fields:

this.articleList = [
    {
        articleId: 1,
        desc: 'xxxxxx',
        author: 'fengxianqi',
        time: 'xxx',
        comments: [
            {
                userId: 2,
                conent: 'xxx'} ] }, { articleId: 2 // ... } / /... ]Copy the code

Suppose we only need some of the fields in the list in our applet. It is not wise to setData the entire articleList if we do not do anything with the data.

Mini program official document: the data configured at a time cannot exceed 1024kB. Do not set too much data at a time.

As you can see, memory is precious, and some models will burst when the articleList data volume is very large, exceeding 1M (I’ve seen it many times on iOS).

Therefore, we need to discard the data returned by the interface, and then setData, going back to our articleList example above, suppose we only need the articleId and author fields. We can do this:

import { getArticleList } from '@/api/article'
export default {
    data () {
        return {
            articleList: []
        }
    }
    methods: {
        getList () {
            getArticleList().then(res => {
                let rawList = res.list
                this.articleList = this.simplifyArticleList(rawList)
            })
        },
        simplifyArticleList (list) {
            return list.map(item => {
                return{articleId: item.articleid, author: item.author}}Copy the code

SimplifyArticleList: simplifyArticleList: simplifyArticleList: simplifyArticleList

[
    {articleId: 1, author: 'fengxianqi'},
    {articleId: 2, author: 'others'}
    // ...
]
Copy the code

Of course, if your requirement is to use all (or most) of your data, there is no need for a layer of streamlining that will not yield much benefit. After all, streamlining specific fields in a function can increase maintenance costs.

PS: In my personal practice, although data filtering increases the maintenance cost, it generally brings great benefits. Therefore, this method is recommended.

2. Data () contains only required data

import xx from 'xx.js'
export default {
    data () {
        return {
            xx,
            otherXX: '2'}}}Copy the code

Some students may be used to import things into data first and then use them in methods, which may be a bad habit in small programs.

Because when I update some data with vue.config. _mpTrace = true, I make a difference between putting it in data and not putting it in data.

So I guess it may be that data will be updated together, for example, if you just want to update otherXX, xx will also be merged with setData.

3. Put static pictures in static

This problem is the same as the above problem. Sometimes we introduce it as import, for example:

<template>
    <img :src="UserIcon">
</template>
<script>
import UserIcon from '@/assets/images/user_icon.png'
export default {
    data () {
        return {
            UserIcon
        }
    }
}
</script>
Copy the code

This results in packaged code where images are stored in Data in Base64 form (long strings), which is not conducive to simplifying data. And when the component is used in more than one place, each component instance carries this long base64 code, further leading to data redundancy.

Therefore, it is recommended to place static images in the static directory and reference them as follows:

<template>
    <img src="/static/images/user_icon.png">
</template>
Copy the code

The code is cleaner.

Take a look at the before and after comparison of the above operation, the user experience is also much smoother.

Swiper optimization

The swiper component provided by the mini program itself does not perform very well, so be careful when using it. There are two ideas:

  • [Optimization] Solve the problem when swiper renders many images
  • I want to ask you about the swiper component

In my case, the idea of dynamically deleting a swiper-Item wasn’t feasible due to requirements (hand swiping caused thrashing). So let it go. But it can still be optimized:

  • Will not showswiper-itemThe pictures inv-ifHide to, and only display when judging current, to prevent performance problems caused by a large number of images rendering.

Iv. Precautions for using VUEX

I’ve written about how to use Vuex in mpvue audio applets. But I ran into a serious performance problem.

1. Problem description

PlayList, currentIndex and currentTime in state.js: playList, currentIndex, currentTime

Const state = {currentIndex: 0, // playList currentTime: 0, // playList: [], // {title:' ', url: ' ', singer: ' '}}Copy the code

Every time the user clicks play audio, the playList of the audio will be loaded first, and then the currentTime will be updated when playing audio. It is found that sometimes the whole applet is very slow when playing audio.

Notice that the audio has to be updated currentTime every second, that is, setData every second, so a little bit of lag is understandable. But I found it was a special card when there was a lot of playList data, like when the playList was 100 or more.

2. Cause of the problem

Vue. Config. _mpTrace = true

When the amount of palyList data is small, the update value caused by the console display is small. When the playList is large, the console displays a large number of data updates.

PS: I tried to increase the number of playList data to 200, and the number of data updates every 500ms is around 800KB.

It is almost certain that updating any field in state will result in setData for the entire state. In my example, even though I’m only updating currentTime each time, I’m still doing a setData operation on all the other fields in state like playList and currentIndex.

3. Solve problems

There are two ideas:

  • Thin down the data stored in state, known as restrictionsplayListThe data can not be too much, some data can exist temporarilystorageIn the
  • vuexusingModuleThis can be ameliorated, although using namespaces can cause some problems.Vuex portal

In general, the latter is recommended. I tried to use the former in the project, also achieved good results, please continue to see the following share.

Fifth, make good use of storage

1. Why make good use of storage

Since the memory of small programs is very precious, it is best to put as little data as possible into memory, i.e. vuEX should store as little data as possible. The storage of a small program supports a maximum of 1MB of data for a single key and a maximum of 10MB for all data stores.

Therefore, infrequently accessed data can be stored in the storage and then stored in the memory when needed, which alleviates the memory shortage. This is similar to the concept of virtual memory in Windows.

2. Storage Memory replacement instance

This example will be a little wordy, really can use the friend can see in detail.

As mentioned above, playList has too much data. When playing an audio track, we only need to keep at most 3 pieces of data in memory, that is, the last song, the playing song, and the next song. We can store the extra playList in storage.

PS: In order to ensure smooth continuous switching of the next song, we can save a little more. For example, I choose to save 5 pieces of data here. In Vuex, there are always two pieces of data before and after the current audio when playing.

// First play background audio async methodfunctionPlayAudio (audioId) {// Get the playList. The playList has a maximum of 5 entries. Const playList = await getPlayList(audioId) // currentIndex const currentIndex = PlayList. FindIndex (item = > item. AudioId = = = audioId) / / background audio enclosing audio = wx. GetBackgroundAudioManager () this.audio.title = playList[currentIndex].title this.audio.src = playList[currentIndex].url // This.updatecurrentindex (index) this.updatePlayList(playList) // UpdateCurrentIndex and updatePlayList are vuex's methods for retrieving the playlist, storing all data in storage, and then returning the first and second data of the current audio. A maximum of five items of data import {loadPlayList} from'@/api/audio'
async functionGetPlayList (courseId, currentAudioId) {loadPlayList is an API method. CourseId is an argument to get the playlist for the current courseletRawList = await loadPlayList(courseId) // simplifyPlayList To filter out some fields const list = this.simplifyPlayList(rawList) // Wx. setStorage({key:'playList',
        data: list
    })
    return subPlayList(list, currentAudioId)
}
Copy the code

The focus is on the subPlayList method, which ensures that the playlist is given a maximum of five pieces of data.

function subPlayList(playList, currentAudioId) {
  letTempArr = [...playList] const count = 5 const middle = parseInt(count / 2) // Index of the midpoint const len = Temparr. length // If the entire original playlist has less than 5 entries, it does not need to be trimmed and returns directlyif (len <= count) {
    returnTempArr} // Find the location of the current audio const index = temparr.findIndex (item => item.audioId === currentAudioId tempArr = tempArr.splice(Math.max(0, Math.min(len - count, index - middle)), count)return tempArr
}
Copy the code

Temparr.splice (math.max (0, index-middle), count) temparr.splice (math.max (0, index-middle), count) Suppose the playList has 10 pieces of data:

  • The current audio is the first audio in the list (index is 0).playList.splice(0, 5)At this time,currentAudioThe index of the 5 data is0, there is noOn aThere are fourThe following piece
  • The current audio is number 2 in the list (index is 1).playList.splice(0, 5)At this time,currentAudioThe index of the 5 data is1, there is oneOn a, 3The following piece
  • The current audio is number 3 in the list (index is 2).playList.splice(0, 5)At this time,currentAudioThe index of the 5 data is2There are twoOn a, 2The following piece
  • The current audio is number 4 in the list (index is 3), truncated from number 1 to 6:playList.splice(1, 5)At this time,currentAudioThe index of the 5 data is2There are twoOn a, 2The following piece
  • The current audio is number 5 in the list (index is 4), truncated from number 2 to 7:playList.splice(2, 5)At this time,currentAudioThe index of the 5 data is2There are twoOn a, 2The following piece
  • .
  • The current audio is number 9 in the list (index is8), the last 5:playList.splice(4, 5)At this time,currentAudioThe index of the 5 data is3There are threeOn a1,The following piece
  • The current audio is the last item in the list (index is9), 5 after interception:playList.splice(4, 5)At this time,currentAudioThe index of the 5 data is4There are fourOn a, there is noThe following piece

It’s a bit wordy. If you are interested in it, no matter where the current audio is, you can always get up to 5 pieces of data before and after the current audio.

The next step is to maintain that the playList in the current VUex always contains the first and second items of the current audio when playing the last or the next song.

Play the next song
function playNextAudio() {
    const nextIndex = this.currentIndex + 1
    if (nextIndex < this.playList.length) {
        // The vuex list can be played directly
        this.audio = wx.getBackgroundAudioManager()
        this.audio.src = this.playList[nextIndex].url
        this.audio.title = this.playList[nextIndex].title
        this.updateCurrentIndex(nextIndex)
        // When it is judged that vuex has reached the boundary of playList, add data from storage to playList again
        if (nextIndex === this.playList.length - 1 || nextIndex === 0) {
          // Get a list of up to 5 entries before and after the current audio
          const newList = getPlayList(this.playList[nextIndex].courseId, this.playList[nextIndex].audioId)
          // The index of the current audio in the 5 items
          const index = newList.findIndex(item= > item.audioId === this.playList[nextIndex].audioId)
          // Update to vuex
          this.updateCurrentIndex(index)
          this.updatePlayList(newList)
        }
    }
}
Copy the code

GetPlayList (); getPlayList (); getPlayList (); getPlayList ();

import { loadPlayList } from '@/api/audio'
async functionGetPlayList (courseId, currentAudioId) {const playList = wx.getStoragesync (courseId, currentAudioId);'playList')
    if(playList && playlist. length > 0 && courseId === playList[0]. CourseId) {// If the cache is hit, it will be returned from directreturn subPlayList(playList, currentAudioId)
    } elseConst list = await loadPlayList(courseId) wx.setstorage ({key: {// no cache hit, const list = await loadPlayList(courseId) wx.setstorage ({key:'playList',
        data: list
      })
      return subPlayList(list, currentAudioId)
    }
}
Copy the code

The same goes for the last one, so I won’t repeat it.

PS: After simplifying the data in Vuex, I made a small application that swiped other pages while playing audio and it worked very well.

Sixth, animation optimization

This problem in mpvue development audio class small program step pit and suggestions have been talked about, interested can move to take a look, here only write an overview:

  • If you use animations, try to use CSS animations instead of wx.createAnimation
  • It is recommended to enable hardware acceleration when using CSS animations

The last

To summarize the main points mentioned above:

  • Open at development timeVue.config._mpTrace = true.
  • Introduce third-party libraries with caution and weigh the benefits.
  • Exercise restraint when adding data to data, and make it as small as possible.
  • Images should be compressed and rendered only when displayed.
  • Vuex keeps data compact and stores storage when necessary.

Performance optimization is a never-ending topic, and I’m still trying to find my way around it.

Welcome to pay attention, will continue to share some of the front-end combat encountered problems and solutions.