Практика оптимизации производительности программы WeChat Mini

оптимизация производительности
Практика оптимизации производительности программы WeChat Mini

Резюме истории:

Эта статья в основном основана на официальных предложениях по оптимизации мини-программ WeChat и плане оптимизации производительности «Шанхайская станция Седьмого сезона открытого класса WeChat 2018 · Специальная сессия мини-программы» для проведения практики оптимизации производительности для наших проектов мини-программы и записи процесс для удобства в будущем. Ознакомьтесь с ним, а также надейтесь помочь другим небольшим партнерам оптимизировать производительность. В конце концов, все оптимизации производительности предназначены для лучшего взаимодействия с пользователем.

Отрабатывается оптимизационная схема добавления зеленых флажков

Общие проблемы с производительностью мини-программ

  • Почему этот апплет такой медленный?
  • Почему этот апплет не скользит и застревает?
  • Почему возникает задержка, когда апплет режет страницы?
  • Почему нет ответа после нажатия, зависает?

Все сценарии этих проблем отражают проблемы с производительностью апплета, которые напрямую влияют на взаимодействие с пользователем.

Как оптимизировать работу мини-программ?

Официальная рекомендация заключается в оптимизации с учетом этих двух аспектов:

  • Начать оптимизацию производительности
  • Оптимизация производительности рендеринга

Начать оптимизацию производительности

В течение всего процесса запуска апплета обычно необходимо выполнить несколько задач:

  • 1. Подготовьте операционную среду (WeChat справится с этим самостоятельно)
  • 2. Загрузите и выполняет соответствующий код код апплета впрыска
  • 3. Визуализация домашней страницы апплета

Разработчики могут оптимизировать скорость запуска мини-программ в разделах 2 и 3.

1. Оптимизация размера пакета кода

Когда апплет открывается в первый раз, он загружает и выполняет пакет кода.По мере увеличения размера пакета кода соответственно увеличивается и время, затрачиваемое на его выполнение. Можно взять следующие варианты:

субподряд

Использовать субподряд

Для разработчиков это может уменьшить размер кода апплета и нести больше функций и сервисов, а для пользователей — быстрее открыть апплет и использовать больше, не влияя на скорость запуска.

Разработчикам рекомендуется разделить на несколько подпакетов в соответствии с разделением функций и загружать подпакет, соответствующий этой функции, только тогда, когда функция необходима.

упражняться

Одна из наших малых программ была разработана более двух лет назад, в начале проектирования мы это не учли, да и функции субподряда малых программ в то время не было. Ну, у нас все еще есть эта проблема.

В документации по разработке апплета WeChat четко указано, что размер всех пакетов апплета должен быть ограничен в пределах 2 М. Если размер превышает размер, его нельзя нормально просмотреть в инструментах разработчика и нельзя загрузить для распространения. способ решения проблемы:

Сжимайте статические ресурсные картинки,потому что алгоритм сжатия апплета очень мало сжимает картинки.Поэтому автор сжимает картинки на раунд,и публично извлекает повторно используемые картинки.Хотя официальная рекомендация-использовать сетевые картинки,но и это необходимо поддерживать статические ресурсы, и если это хлопотно, я сдаюсь.

Была убрана волна устаревших страниц и неиспользуемых третьих лиц в проекте.

Многие проекты сейчас упакованы в разные подпакеты через webpack, а ресурсы оптимизированы в виде ленивой загрузки, в апплете тоже предусмотрена эта функция: подпакет, автор делит страницы и логику под одной функцией по принципу разделения функций. Размещается в том же каталоге, что и подпакет.

После субподряда:

Примечание: 1. Пользовательские сторонние компоненты необходимо поместить в основной пакет, а файл miniprogram_npm будет загружен непосредственно в основной пакет 2. Страница переключения вкладок мини-программы должна быть помещена в основной пакет.

Предварительная загрузка подпакета

Предварительная загрузка подпакета предназначена для решения проблемы задержки при входе на страницу подпакета в первый раз. Если субконтракты могут быть загружены до того, как пользователь перейдет на страницу субконтрактов, задержка при входе на страницу субконтрактов может быть максимально сокращена.

упражняться

Пользователь выполняет определенную операцию, а затем загружает подпакет.Отложенная операция приводит к плохому взаимодействию с пользователем, поэтому автор устанавливает предварительную загрузку подпакета для вышеуказанного подпакета. существуетapp.jsonКонфигурация в файле:

"preloadRule": {
    "pages/work/index": {
      "network": "all",
      "packages": [
        "package-work",
        "package-field-statistics"
      ]
    },
    "pages/appeal/index": {
      "network": "all",
      "packages": [
        "package-appeal"
      ]
    }
},

Не рекомендуется предварительно загружать все подпакеты за один раз, так как эта операция также приводит к проблемам с производительностью.

Независимый субподряд

Некоторые сценарии в апплете (такие как рекламные страницы, страницы активности, платежные страницы и т. д.) обычно имеют менее сложные и относительно независимые функции и предъявляют высокие требования к производительности при запуске. С автономными подпакетами вы можете работать независимо от основного пакета и других подпакетов. При входе в апплет со страницы в независимом подпакете загружать основной пакет не нужно.

Разработчикам рекомендуется помещать некоторые страницы, требующие высокой производительности при запуске, в специальные независимые подпакеты.

упражняться

Подходящей сцены в проекте нет, и она не отрабатывалась.

2. Оптимизация рендеринга первого экрана

1. Предварительный запрос данных первого экрана

Когда большинство апплетов отображают домашнюю страницу, им приходится полагаться на данные интерфейса сервера, а запрос интерфейса помещается в жизненный цикл страницы.onLoadвместоonReadyвнутри.

упражняться

Отслеживайте загрузку страницы, проверяйте статус входа и запрашивайте данные страницы.

onLoad: function (options) {
    app.checkAuth((error, token) => {
      if (error) {
        return
      }
      // 请求该页面的数据
    })
  },

2. Кэшировать данные запроса

Апплет предоставляет возможность асинхронного чтения и записи в локальный кеш, например wx.setStorageSync, данные хранятся локально, и отдача будет быстрее, чем сетевой запрос.

упражняться

После успешного входа в систему токен пользователя и информация о пользователе могут быть кэшированы локально, не забудьте очистить кеш при выходе из системы, 😂.

/**
 * 设置本地 token 缓存
 * @param {Object} session 服务器返回的数据
 * @param {String} session.access_token 存取token
 * @param {String} session.refresh_token 刷新token
 * @param {String} session.expires_in 有效期限,以秒为单位
 */
export function set(session) {
  const localSession = Object.assign({}, session, {
    expires_timestamp: getExpireTimestamp(session.expires_in)
  });
  wx.setStorageSync(SESSION_KEY, localSession);

  _token = session.access_token;
}

export function clear() {
  wx.removeStorageSync(SESSION_KEY);
  clearTimeout(refresh_timer);

  _token = null;
}

3. Оптимизируйте данные в верхней части страницы

Разработчикам рекомендуется откладывать запрос некритических данных рендеринга, чтобы сократить задержку сетевого запроса, и стараться не помещать данные, не связанные с рендерингом слоя представления, в данные, чтобы избежать передачи ненужных данных и ускорить время завершения рендеринга первого экрана.

упражняться

В случае запроса деталей по id, id не требуется в слое рендеринга, поэтому id можно определить в данных без id:

// 原来代码
data: {
    id: ‘’,
    // ….
},
onLoad: function (options) {
    	this.setData({
		id: options.id
	})
	// ….
}

// 改写后 不把id定义到data中
data: {
    // ….
},
app.checkAuth((error, token) => {
      const id = options.id === undefined ? '' : options.id;
      this.id = id 
})

Данные, возвращаемые интерфейсом, должны обрабатываться, а не вставляться напрямую в данные, чтобы уменьшить двухпоточный возврат избыточных данных. Это также часть оптимизации прореживающих данных выше сгиба.

4. Избегайте блокировки рендеринга

В процессе запуска апплета app.onLaunch, app.onShow, page.onLoad, page.onShow, page.onReady будут выполняться последовательно, поэтому старайтесь избегать использования API синхронизации в конце Sync в таких жизненных циклах, как wx.setStorageSync , wx.getSystemInfoSync и т. д.

упражняться

Нет такой пользы в проекте, предвидя. 😄

Оптимизация производительности рендеринга

Уровень представления апплета в настоящее время использует WebView в качестве носителя рендеринга, а уровень логики использует независимый JavascriptCore в качестве рабочей среды. Архитектурно и WebView, и JavascriptCore являются независимыми модулями и не имеют каналов для прямого обмена данными. В настоящее время передача данных между уровнем представления и уровнем логики фактически реализована с помощью EvaluateJavascript, предоставляемого с обеих сторон. То есть данные, передаваемые пользователем, должны быть преобразованы в строку для передачи, и в то же время преобразованное содержимое данных встраивается в JS-скрипт, а затем передается в независимые среды с обеих сторон путем выполнения JS-скрипт.

На выполнение оценки Javascript будут влиять многие аспекты, и данные, поступающие на уровень представления, не поступают в режиме реального времени.

** Распространенные ошибки операции setData **

1. Чаще заходите в setData

Это приводит к двум последствиям:

  • В Android пользователи будут чувствовать себя застрявшими при скольжении, а обратная связь по операции серьезно задерживается, потому что поток JS компилируется, выполняется и рендерится, не в состоянии вовремя передавать события пользовательских операций на логический уровень, а логический уровень не может своевременно передать обработка результатов операции на уровне логики, уровень представления;
  • Отрисовка происходит с задержкой.Поскольку JS-поток WebView всегда занят, время связи между логическим уровнем и уровнем страницы увеличивается, и с момента получения сообщения с данными на уровне представления прошло несколько сотен миллисекунд.Результат рендеринга не в реальном времени;

упражняться

В настоящее время код проекта относительно стандартизирован, мы не вызываем setData как обычный объект, мы знаем, что каждое использование требует связи между двумя потоками, а затем рендерится WebView. Вау, отлично.

2. Передайте много новых данных каждый раз, когда setData

Из базовой реализации setData видно, что наша передача данных на самом деле представляет собой процесс сценария AssessmentJavascript.Когда количество данных слишком велико, время компиляции и выполнения сценария увеличивается, занимая поток WebView JS.

упражняться

В настоящее время объем данных на каждом интерфейсе невелик, и величина данных не достигла уровня, влияющего на выполнение шагов, при необходимости оптимизируйте его.

3. SetData на странице фонового состояния

Когда страница переходит в фоновое состояние (пользователь невидим), она не должна продолжать setData, рендеринг страницы фонового состояния не может ощущаться пользователем, а страница фонового состояния в setData также будет вытеснять выполнение переднего плана. страница.

упражняться

На странице A есть таймер. В это время открыта страница B. Таймер страницы A все еще работает и продолжает вытеснять ресурсы страницы B. Страница B зависает, но это не проблема производительности, вызванная страницей B. Проблема не проста в устранении. Я надеюсь, что каждый может быть человеком, у которого есть начало и конец, а таймер нужно очищать, когда он больше не нужен. Демонстрация ниже, таймер находится вonHideбыть очищенным. Помните, чтобы помнить👇

/**
   * 生命周期函数--监听页面显示
   */
onShow: function () {
    clearTimeout(getTodaytime)
    this.updateNowTime()
},

/**
   * 生命周期函数--监听页面隐藏
 */
onHide: function () {
    // 取消定时器 防止小程序内存不足,崩溃
    clearTimeout(getTodaytime)
},
updateNowTime() {
    getTodaytime = setInterval(() => {
      const myDate = new Date(); 
      const hours = myDate.getHours())
      const minutes = myDate.getMinutes())
      const seconds = myDate.getSeconds())

      const newTime = hours + ':' + minutes + ':' + seconds;
      this.setData({
        newTime: newTime
      })
    }, 1000)
  },

2. Неправильное использование пользовательских событий

  • Чрезмерное использование bindTap и bindCatch
  • Неправильное использование onPageScroll

упражняться

В проектах не показано использование этого события.

3. Используйте пользовательские компоненты

В сценариях, требующих частых обновлений, обновление пользовательских компонентов выполняется только внутри компонента и не зависит от сложности других частей страницы.

упражняться

Функция пробивки в апплете нашего проекта должна отображать текущее время: час,минута и секунда.Здесь таймер используется для частого обновления setData.Здесь подходит извлечь таймер как компонент и пусть он обновить данные внутри компонента. Не влияет на другие части страницы.

Суммировать

Производительность загрузки при запуске мини-программы:

  • Контролируйте размер пакета кода
  • Загрузка подпакета
  • Выше опыта сгиба

Производительность рендеринга апплета:

  • Избегайте неправильного использования setData
  • Разумное использование сообщений об инцидентах
  • Избегайте неправильного использования onPageScroll
  • Оптимизация узлов просмотра
  • Используйте пользовательские компоненты

Примечание. PPT в тексте взят из «Специальная программа малого бизнеса Шанхайской станции Седьмого сезона открытого класса WeChat 2018».

Ссылаться на