Резюме и опыт разработки апплета WeChat

WeChat JSON JavaScript Апплет WeChat

0 Предисловие


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

1 Базовые знания и концепции мини-программ WeChat


Разработка апплета Wechat, начать очень просто, достаточно посмотреть официальные документыМини-программа Простой учебник. Как подать заявку на учетную запись апплета, как разработать свой первый апплет и как его опубликовать, в этой серии официальных документов по эксплуатации Hello World есть практическое обучение. Каждый шаг разработки апплета включен в предоставленный документ о возможностях.Лично я считаю, что при разработке апплета вы должны прочитать документ, если у вас есть что-нибудь или ничего, потому что обновление апплета происходит относительно быстро, и мы можем упустить некоторые небольшие возможности. , так что читайте больше документации.

1.1 Кратко опишите структуру каталогов и app.json


Структура файловых каталогов очень гибкая.

Давайте сначала посмотрим на структуру каталогов файлов проекта апплета.

文件目录结构

За исключением app.json, который должен находиться в корневом каталоге, остальные файлы являются необязательными и могут быть удалены. И где можно разместить файл подкачки, главное, чтобы он настраивался на страницах в app.json. Можно сказать, что он очень гибкий. Вы также можете поместить несколько страниц в одну и ту же папку (я уверен, что вы этого не сделаете, так что зачем тратить себя впустую).

Ниже приводится краткое описание каждого файла:

Глобальный файл конфигурации app.json

Для проекта апплета наиболее важным файлом является файл app.json, который также является идентификатором для инструмента разработки, чтобы определить, является ли папка проектом апплета. При создании проекта с помощью инструментов разработчика, если выбрана пустая папка, будет создан новый проект. Если это папка с файлами, то посмотрит есть ли в папке файл app.jon, если есть, то посчитает его проектом апплета и откроет проект, если в папке нет app.json файл, проект не может быть создан.

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

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

Ниже описаны глобальные параметры конфигурации апплета:

Уведомление:

  • Все ключи элементов конфигурации должны быть заключены в двойные кавычки, а значение значения также должно быть заключено в двойные кавычки, если значение имеет строковый тип.Одинарные кавычки не поддерживаются.
  • Поскольку функция апплета повторяется очень быстро, а версия базовой библиотеки обновляется очень быстро, поэтому следующее введение представляет собой последнюю версию библиотеки 2.4.0 на данный момент.
  • pages

    "pages": [
        "pages/index/index",
        "pages/log/log"
    ]

В app.json параметр pages является обязательным. Этот элемент конфигурации регистрирует адреса всех страниц апплета, каждая из которых является страницейпуть + имя файла. Сконфигурированная строка на самом деле представляет собой путь wxml каждой страницы с удаленным суффиксом .wxml. Потому что фреймворк автоматически найдет в пути четыре файла: .json, .js, .wxml и .wxss для интеграции. Это означает, что имена трех файлов .json, .js и .wxss должны совпадать с именами файлов .wxml, иначе они не вступят в силу. Поэтому на странице должен быть как минимум файл .wxml.

Суммировать:

  • Файлы .json, .js и .wxss страницы должны иметь то же имя, что и файл .wxml, в противном случае это не сработает.
  • Каждая страница должна быть зарегистрирована в разделе pages.Зарегистрированной страницы нет.Если вы не зайдете на нее, компиляция может пройти.При попытке зайти на страницу будет сообщено об ошибке.
  • Вы можете быстро создать новую страницу, добавив опцию под страницами, и инструмент разработки автоматически сгенерирует соответствующий файл.
  • window

  "window":{
    "enablePullDownRefresh": ture,
    "navigationStyle": "custom"
  }

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

//去掉默认的导航栏,轻松实现全面屏
"navigationStyle": "custom" , 
//开启自带的下拉刷新,减少自己写样式
"enablePullDownRefresh": ture, 
  • tabBar

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

  • networkTimeout

Это время ожидания сетевого запроса.Вы можете установить время ожидания для различных типов запросов, таких как wx.request, wx.uploadFile и т. д. На самом деле, мы часто игнорируем эту опцию.По умолчанию апплет имеет тайм-аут 60 с, но мы должны вручную установить меньшее значение, потому что наш интерфейс обычно выполняет запрос в течение 10 с (если он превышает 10 с, то настало время для вам оптимизировать), так что если есть проблема с сетью или сервером, пользователю будет предложено подождать 60 секунд, а затем произойдет сбой.

Некоторое время назад из-за небольшой проблемы со шлюзом сервера компании некоторые запросы не могли быть подключены, и возникало большое количество тайм-аутов подключения. С помощью ранее добавленного плагина сбора информации об ошибках (это оптимизация производительности, упомянутая ниже) я увидел, что многие интерфейсы возвращают тайм-аут 60 с. Недружелюбно позволять пользователям ждать 60 секунд и все равно терпеть неудачу. Поэтому этот тайм-аут обычно устанавливается на 15–30 секунд.

  • debug

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

  • functionalPages

Это используется в сочетании с подключаемым модулем, поскольку подключаемый модуль апплета WeChat очень ограничен, API, предоставляемый в подключаемом модуле, очень ограничен, а wx.login и wx.requestPayment не могут использоваться в подключаемом модуле. , Если вам нужно получить информацию о пользователе и произвести платежи, вы должны пройти Функционал, предоставляемый плагином, также реализован. Когда подключаемый модуль вашего апплета включает функцию подключаемого модуля, вы должны установить для этого параметра значение true.

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

  • plugins

    "plugins": {
        "myPlugin": {
            "version": "1.0.0",
            "provider": "wxidxxxxxxxxxxxxxxxx"
        }
    }

Когда апплет использует подключаемый модуль, он должен быть объявлен здесь. Апплет, открытый самим апплетом, не может использоваться сам по себе

  • navigateToMiniProgramAppIdList

    "navigateToMiniProgramAppIdList": [
        "wxe5f52902cf4de896"
    ]

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

  • usingComponents

  "usingComponents": {
    "hello-component": "plugin://myPlugin/hello-component"
  }

Прежде чем использовать пользовательские компоненты или компоненты, предоставляемые плагинами, вы должны объявить их здесь.

1.2 Запуск и жизненный цикл мини-программы


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

Есть две ситуации, когда апплет запускается: «холодный запуск» и «горячий запуск». Если пользователь уже открыл определенный апплет, а затем снова открывает апплет в течение определенного периода времени, нет необходимости перезапускать в это время, просто переключите апплет в фоновом состоянии на передний план, этот процесс является горячим запуск; холодный запуск относится к пользователю Когда апплет открывается в первый раз или открывается снова после того, как апплет активно уничтожается WeChat, апплет необходимо перезагрузить и запустить.

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

  1. Апплет сначала обнаружит, есть ли локальный пакет кода, затем использует локальный пакет кода для запуска апплета, а затем асинхронно обнаружит удаленную версию. Это автономная возможность апплета.По сравнению с H5 это преимущество, и оно может ускорить запуск апплета.
  2. Когда локально имеется небольшой пакет программного кода, он асинхронно запрашивает, есть ли на удаленном конце последняя версия. Если есть, загрузите его локально, но на этот раз при запуске все равно будет использоваться предыдущий код. Поэтому, когда мы выпустили последнюю версию, пользователям потребуется два холодных запуска, прежде чем они смогут использовать последнюю версию. Если вы хотите, чтобы пользователи использовали последнюю версию после холодного запуска, вы можете использовать API обновления версии, предоставляемый апплетом.возобновить. Код выглядит следующим образом: если в функцию onShow файла app.js добавлен следующий код, при каждом обновлении апплета пользователю будет предлагаться обновить апплет. Однако каждый раз, когда подсказка обновляется, это в определенной степени влияет на взаимодействие с пользователем. В сочетании с внутренней конфигурацией каждый раз, когда вы входите и читаете конфигурацию, вы можете понять, следует ли обновлять версию в соответствии с вашими потребностями.Например, если вы должны обновить пользователя, чтобы использовать его, вы можете использовать принудительный Обновить. Для некоторых младших версий это принудительное обновление не требуется.
    if (wx.canIUse('getUpdateManager')) {
        //检测是否有版本更新
        var updateManager = wx.getUpdateManager()
        updateManager.onCheckForUpdate(function (res) {
            // 请求完新版本信息的回调,有更新
            if (res.hasUpdate) {
                wx.showLoading({
                    title: '检测到新版本',
                })
            }
        })
        updateManager.onUpdateReady(function () {
            wx.hideLoading();
            wx.showModal({
                title: '更新提示',
                content: '新版本已经准备好,是否重启应用?',
                success: function (res) {
                    if (res.confirm) {
                        //清楚本地缓存
                        try {
                            wx.clearStorageSync()
                        } catch (e) {
                            // Do something when catch error
                        }
                        // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
                        updateManager.applyUpdate()
                    }
                }
            })
        })
        updateManager.onUpdateFailed(function () {
            // 新的版本下载失败
            console.log('新版本下载失败');
        })
    }

1.3 Инструменты разработки


Для небольших инструментов разработки программ нет никого, кто мог бы удовлетворить разработчиков, по крайней мере, я не удовлетворен, хахаха! предоставлено WeChatИнструменты разработчика WeChat. Только компилятор не работает, все остальное работает. Однако из-за разных ядер средств разработки платформы ios и android для запуска небольших программ. Так что иногда нет проблем с инструментом разработки, но есть проблема с реальной машиной, особенно со стилем, который можно задать в инструменте разработки.Автодополнение стиля при загрузке кодадля решения большинства проблем. Кроме того, инструмент разработчика WeChat предоставляет функцию отладки реальной машины, что очень удобно для отладки реальной машины.

Также есть возможность настроить условия компиляции

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

1.4 Тест-аудит-онлайн-вещи


Легитимное доменное имя запроса доменного имени сервера может быть изменено только 5 раз в месяц. Поэтому его не следует добавлять каждый раз, когда запрашивается новое доменное имя. На этапе разработки установите флажок Не проверять легальные доменные имена в инструменте разработчика WeChat, и вам необходимо включить режим отладки на реальной машине.Вы можете запросить любое доменное имя или даже IP-адрес без предварительной настройки легального доменного имени. После завершения разработки настройте все легальные доменные имена одновременно, отмените непроверку легальных доменных имен в инструменте разработчика WeChat, отключите режим отладки на реальной машине, а затем запустите тест.

Используйте интерфейс пробной версии + онлайн-среда, которая точно такая же, как онлайн-среда, поэтому перед выпуском используйте пробную версию + онлайн-среду, чтобы пройти ее. Если проблем нет, то после релиза все будет хорошо.

QR-код апплета может успешно вернуть QR-код, только если онлайн-версия выпущена для вызова сгенерированного интерфейса QR-кода апплета. Более того, распознавание QR-кода является онлайн-версией, поэтому неопубликованные мини-программы не могут генерировать QR-коды.

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

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

2 Выделите несколько компонентов


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

2.1 web-view


Появление веб-просмотра позволяет переключаться между мини-программами и веб-страницами H5. Поместив страницу H5 в веб-представление, страницу H5 можно запустить в апплете. В то же время вы также можете вернуться на страницу апплета на странице H5. Можно сказать, что это приносит большое удобство, но в то же время из-за множества ограничений веб-просмотра пользоваться им не очень удобно.

  1. Страница H5, которую нужно открыть, должна быть настроена в фоновой бизнес-странице, а также есть проверка службы. Кроме того, страница H5 должна быть с протоколом https, иначе ее нельзя будет открыть.
  2. В веб-представлении общий доступ не может быть вызван на странице. Если вам нужно поделиться, например, вернитесь на исходную страницу апплета.
  3. Существует проблема со связью H5 между апплетом и веб-представлением. Апплет передается в веб-представление, и неконфиденциальная информация может быть передана через URL-адрес страницы. Если это конфиденциальная информация, такая как токен пользователя и т. д., сервер может быть перенаправлен, например, запросить адрес с сервера, позволить ему записать конфиденциальную информацию в файл cookie, а затем перенаправить на нашу страницу H5. После этого страница H5 может брать эти конфиденциальные данные в куках или только по http и выводить их напрямую при отправке запроса.
  4. Страница перезагружается каждый раз, когда значение src в веб-представлении изменяется. Поэтому, когда параметр сплайсинга src, вам нужно сначала назначить его переменной, а затем сплайсировать его, а затем установить Data в src веб-представления за один раз, чтобы предотвратить повторное обновление страницы.
  5. Начиная с версии клиента WeChat 6.7.2,navigationStyle: customНедействительно для компонентов. Это означает, что при использовании веб-представления встроенная панель навигации не может быть удалена.
  6. Поскольку панель навигации не может быть удалена, здесь есть огромная яма. Осознайте проблему полноэкранного эффекта. Если вы хотите получить полноэкранную страницу H5, просто не скользите и отображайте весь контент в полноэкранном режиме. Тогда, если вы используетеwidth:100%;height:100%, вы заметите, что в нижней части страницы может отсутствовать абзац. Над:

Поскольку веб-просмотр по умолчанию является полноэкранным, то есть ширина и высота веб-просмотра такие же, как ширина и высота экрана. Тогда высота страницы H5 составляет 100%, то есть высота относительно веб-представления, которая также является высотой экрана. Но ключевой вопрос:Страницы H5 в веб-представлении отображаются из-под панели навигации.. Это приводит к тому, что страница H5 выходит за пределы экрана и не может обеспечить полноэкранный эффект.

Решение

Некоторое время назад я столкнулся с этой проблемой в реальном проекте. Мы собираемся сделать игру H5, и требование - полный экран. В начале я также установил высоту на 100%. Позже выяснилось, что нижняя часть отсутствует. Мое решение относительно грубое, если есть лучшее решение, пожалуйста, прокомментируйте и обменяйтесь. Мое решение: путем соединения параметров ширины и высоты в URL-адресе страницы H5 ширина и высота рассчитываются вне веб-представления. Страница H5 напрямую считывает ширину и высоту URL-адреса и динамически устанавливает ширину и высоту страницы. Расчет высоты страницы, согласно приведенному выше рисунку, очевидно, представляет собой высоту экрана за вычетом высоты панели навигации. Ширина одинаковая, прямо ширина экрана.

Но проблема возникает снова, кажется, нет возможности получить высоту панели навигации. Причем у разных моделей мобильных телефонов высота навигационной панели разная. После сравнения панели навигации и высоты экрана нескольких моделей. Я нашел правило, что высота панели навигации имеет определенную связь с высотой экрана и соотношением сторон экрана. Таким образом, это соотношение было рассчитано на основе нескольких моделей. Это решает проблему адаптации более 95% мобильных телефонов, и лишь несколько моделей плохо адаптированы. К базовой реализации полноэкранного эффекта. Конкретный код выглядит следующим образом:

onLoad (options) {
    //同步获取屏幕信息,现在用到的是屏幕宽高
    var res = wx.getSystemInfoSync();
	if (res) {
		var widHeight = res.screenHeight;
		//对于大多数手机,屏幕高度/屏幕宽度 = 1.78。此时导航栏占屏幕高度比为0.875
		var raito = 0.875;
		if (res.screenHeight / res.screenWidth > 1.95) {
		    //对于全屏手机,这个占比会更高些
			raito = 0.885;
		} else if (res.screenHeight / res.screenWidth > 1.885) {
			raito = 0.88;
		}
		//做兼容处理,只有微信版本库高于6.7.2,有导航栏才去兼容,否则可以直接使用高度100%。res.statusBarHeight是手机顶部状态栏高度
		//如果微信版本号大于6.7.2,有导航栏
		if (util.compareVersion(res.version, "6.7.2") > 0) {
			widHeight = Math.round(widHeight * raito) + (res.statusBarHeight || 0);
		}
		this.setDate({
		    //将H5页面宽高拼接在url上,赋值给web-view的src即可加载出H5页面
		    webview_src: util.joinParams(h5_src, {
		        "height": widHeight, 
		        "width": res.screenWidth
		    })
		})
	}
}

2.2 scroll-view


Когда мы хотим добиться эффекта скольжения в области, на странице H5 мы устанавливаемoverflow-y: scrollВот и все. Но в апплете такого атрибута нет. Требуется тег scroll-view. Для конкретной операции мы можем просмотреть файлscroll-view.

Позиционирование точки привязки часто используется в разработке интерфейса.На страницах H5 мы добавим # после URL-адреса, чтобы добиться эффекта позиционирования точки привязки. Но это не работает в апплете, потому что это не браузер, который отображает страницу в апплете, и он не может отслеживать изменение значения Hash в реальном времени. Но с прокруткой мы можем добиться эффекта точки привязки. В основном используйте свойство scroll-into-vie для прямой реализации кода.

scroll-into-view | Строка | Значение должно быть идентификатором дочернего элемента (идентификатор не может начинаться с цифры). Установите, в каком направлении можно прокручивать, затем прокрутите до элемента, в каком направлении

wxml-файл

    <!--toView的值动态变化,当toView为luckydraw时,会定位到id为luckydraw的view
    需要注意的是,这里需要设置高度为屏幕高度-->
    <scroll-view scroll-y scroll-into-view="{{toView}}" 
    scroll-with-animation = "true" style="height: 100%; white-space:nowrap">
        <view id="top"></view>
        <view id="luckydraw"></view>
        <view id="secskill"></view>
    <scroll-view>

2.3 canvas


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

3 внушительная коллекция


Отправка сообщения пользователю очень важна для небольшой программы, она может вызвать пользователя обратно, а направляющий эффект очень очевиден. Мы можем отправлять сообщения пользователям мини-программы с помощью шаблонных сообщений, но только если мы получим openid и formid. Когда пользователь входит в систему, мы можем получить его openid. И пока пользователь нажимает, мы можем получить формустать грозным. Итак, формид очень важен. Мы можем заранее собирать формы и отправлять сообщения пользователям, когда это необходимо. Мы можем обернуть каждую кнопку тегом формы, и пока существует поведение пользователя при нажатии, формад может быть собран.

    <form bindsubmit="formSubmit" report-submit='true'>
        <button  formType="submit">点击</button>
    </form>

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

  1. Оберните тег формы в самый внешний слой всей страницы, не каждая кнопка будет обернута, поэтому, пока она находится на странице.formTpye=submitКнопка может получить форму, когда она нажата.
  2. formid хранится в массиве глобальных переменных и отправляется один раз, когда апплет переключается в фоновый режим.
  3. Для сообщений, которые нужно отправить в режиме реального времени, значение не добавляется в глобальный массив, а сохраняется напрямую в переменной страницы.

wxml-файл

    <!--在整个页面的最外层包裹form标签,这样就不同对每个button都包裹一个form标签,代码简洁-->
    <form bindsubmit="formSubmit" report-submit='true'>
        <view>页面内容</view>
        <view>页面内容</view>
        <button  formType="submit">点击</button>
        <view>页面内容</view>
        <view>
            <button  formType="submit">点击</button>
        </view>
    </form>

файл page.js

    //每次用户有点击,都将formid添加到全局数组中
    formSubmit(e) {
        //需要实时发送的,不添加
        if(e.target.dataset.sendMsg){
            formid =  e.detail.formId;
            return;
        }
        app.appData.formIdArr.push(e.detail.formId);
    }

app.js

    onHide: function () {
        //小程序切到后台时上传formid
        this.submitFormId();
    },

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


От открытия апплета пользователем до уничтожения апплета мы можем думать о том, что можно оптимизировать. Во-первых, это скорость открытия. Скорость открытия апплета напрямую влияет на удержание пользователей. В бэкенде апплета загружаются данные мониторинга производительности под сигналом мониторинга центра эксплуатации и обслуживания Мы можем видеть данные, связанные с загрузкой, такие как общее время, затраченное на запуск апплета, время загрузки и первый рендеринг. время. Скорость открытия здесь — это на самом деле общее время, необходимое для запуска апплета. Он включает в себя загрузку пакета кода, первый рендеринг и инициализацию внутренней среды WeChat. На этом этапе все, что мы можем сделать, этоКак ускорить загрузку пакетов кода и сократить время первого рендеринга

После представления апплета пользователю возникает следующий вопрос: как улучшить взаимодействие с пользователем и повысить надежность апплета. В каждой программе есть ошибки. Просто мы его не нашли, хотя на этапе тестирования мы провели исчерпывающее тестирование. Однако в реальной производственной среде разные пользовательские среды и разные пути работы могут в любой момент вызвать некоторые скрытые ошибки. В настоящее время, если пользователь не сообщит нам об этом, мы не узнаем. Значит надо дать нашему апплетуУвеличение сбора информации об ошибках, ошибка скрипта js, что означает, что вся программа зависает и не может реагировать на действия пользователя. Поэтому об ошибках скрипта во время выполнения мы должны сообщать о них. Своевременно исправляйте возникающие ошибки, повышайте надежность программы и улучшайте взаимодействие с пользователем.

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

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

4.1 Делайте мини-программы быстрее


Есть два основных фактора, которые делают апплет быстрым: загрузка пакета кода и рендеринг первого экрана. Давайте посмотрим на данные:

Размер кода апплета предыдущего состояния составляет около 650 Кб, что составляет время загрузки (хотя оно связано с пользовательской сетью, но это среднее время для всех пользователей) составляет около 1,3 с. Но после оптимизации пакет кода уменьшается примерно до 200кб. Время загрузки составляет всего около 0,6 с. Таким образом, пакет кода уменьшается на 500кб, а время загрузки может быть уменьшено на 0,5с. Эти данные по-прежнему очень ясны. Поэтому наш пакет кода апплета должен быть как можно меньше, не затрагивая бизнес-логику. Итак, как уменьшить размер пакета кода? Вот несколько точек для справки

  1. Потому что, когда мы загружаем код на сервер WeChat, он сжимает наш код, поэтому пакет кода, загруженный пользователем, не соответствует размеру нашей разработки. В связи с этим нет необходимости удалять пустые строки и удалять комментарии при разработке. В деталях проекта средства разработки вы можете увидеть последний размер загрузки, который является окончательным размером, используемым пользователем. Если вы чувствуете, что сжатие WeChat недостаточно хорошее, вы можете использовать сторонний инструмент для сжатия нашего кода и загрузить его снова, а затем сравнить эффект, чтобы увидеть, меньше ли он. Это не было использовано. Если есть хороший инструмент, пожалуйста, порекомендуйте его.
  2. Предотвратить переход статических файлов ресурсов на наш собственный сервер или cdn. Небольшая программа, наиболее занимающая место часто файл изображения. Следовательно, мы можем извлечь его, а файл изображения можно получить асинхронно, а затем получить после запуска апплета. Таким образом, пакет кода будет намного меньше.
  3. Используйте загрузку подпакетов. Апплет предоставляет функцию загрузки подпакетов. Если ваш апплет очень большой, вы можете рассмотреть возможность использования функции загрузки подпакета, чтобы сначала загрузить необходимый код функции. Это может значительно уменьшить размер пакета кода.

Далее идет рендеринг первого экрана.Как видно из жизненного цикла апплета на рисунке выше, после загрузки кода домашней страницы с домашней страницей для завершения рендеринга этот период времени является временем белого экрана, т.е. , время первого рендеринга. В этот период основными задачами апплета являются: загрузка кода домашней страницы, создание слоев View и AppService, первичная передача данных и отрисовка страницы. В этих четырех шагах загрузите код домашней страницы, как упоминалось ранее; создание слоев View и AppService выполняется WeChat, который связан с мобильным телефоном пользователя, который не находится под нашим контролем. Что мы можем сделать, так это сократить начальное время передачи данных и время рендеринга страницы.

  1. Мы знаем, что объект данных в page.js будет передавать слой представления через конвейер данных для рендеринга страницы при первом рендеринге. Поэтому мы должны контролировать размер этого объекта данных. Для данных, не связанных с визуализацией вида, не помещайте их в данные, вы можете установить глобальную переменную для их сохранения.
    Page({
        //与页面渲染有关的数据放这里
        data: {
            goods_list:[]
        },
        //与页面渲染无关的数据放这里
        _data: {
            timer: null
        }
    })
  1. Скорость рендеринга страницы также связана со структурой DOM HTML. Возможностей для оптимизации в этом плане очень мало, то есть написать качественный html код, уменьшить вложенность dom и сделать отрисовку страницы чуть быстрее.

4.2 Усильте апплет


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

Сбор ошибок скрипта

Для сбора ошибок сценария это относительно просто, потому что функция onError, прослушивающая ошибки, предоставляется в app.js.

Просто информация об ошибке включает в себя более подробную информацию об ошибке, такую ​​как стеки, и нам такая информация не нужна при загрузке.Во-первых, это тратит впустую пропускную способность, а во-вторых, это выглядит усталым и бесполезным. Нам нужна следующая информация: тип ошибки, описание сообщения об ошибке, местоположение ошибки.

thirdScriptError
aa is not defined;at pages/index/index page test function
ReferenceError: aa is not defined
    at e.test (http://127.0.0.1:62641/appservice/pages/index/index.js:17:3)
    at e.<anonymous> (http://127.0.0.1:62641/appservice/__dev__/WAService.js:16:31500)
    at e.a (http://127.0.0.1:62641/appservice/__dev__/WAService.js:16:26386)
    at J (http://127.0.0.1:62641/appservice/__dev__/WAService.js:16:20800)
    at Function.<anonymous> (http://127.0.0.1:62641/appservice/__dev__/WAService.js:16:22389)
    at http://127.0.0.1:62641/appservice/__dev__/WAService.js:16:27889
    at http://127.0.0.1:62641/appservice/__dev__/WAService.js:6:16777
    at e.(anonymous function) (http://127.0.0.1:62641/appservice/__dev__/WAService.js:4:3403)
    at e (http://127.0.0.1:62641/appservice/appservice?t=1543326089806:1080:20291)
    at r.registerCallback.t (http://127.0.0.1:62641/appservice/appservice?t=1543326089806:1080:20476)

Это строка сообщения об ошибке, далее мы ее перехватываем и нам остается только получить нужную нам информацию. Мы обнаружили, что эта строка регулярна. Первая строка — это тип ошибки, вторая строка — сведения об ошибке и ее местонахождение, разделенные символом «;». Таким образом, мы все еще можем легко получить информацию, которую хотим.

    //格式化错误信息
    function formateErroMsg(errorMsg){
        //包一层try catch 不要让信息收集影响了业务
        try{
            var detailMsg = '';
            var detailPosition= '';
            var arr = errorMsg.split('\n')
            if (arr.length > 1) {
                //错误详情和错误位置在第二行并用分好隔开
                var detailArr = arr[1].split(';')
                detailMsg = detailArr.length > 0 ? detailArr[0] : '';
                if (detailArr.length > 1) {
                    detailArr.shift()
                    detailPosition = detailArr.join(';') 
                }
            }

            var obj = {
                //错误类型就是第一行
                error_type: arr.length > 0 ? arr[0] : '',
                error_msg: detailMsg,
                error_position: detailPosition
            };
            return obj
        }catch(e){}
    }

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

Сбор информации об ошибках HTTP-запросаДля метода сбора информации об ошибках http-запроса мы стараемся не закапывать точку насильственно и добавлять нашу точку закапывания перед отправкой каждого запроса. Это слишком много работы и трудно поддерживать. Поэтому мы можем начать снизу,Перехватить запрос wx.request. Используйте Object.definePropert, чтобы переопределить запрос объекта wx. Конкретная реализация выглядит следующим образом

function rewriteRequest(){
	try {
      	const originRequest = wx.request;
		Object.defineProperty(wx, 'request', {
		  	configurable:true,
		  	enumerable: true,
		  	writable: true,
			value: function(){
				let options = arguments[0] || {};
				//对于发送错误信息的接口不收集,防止死循环
				var regexp = new RegExp("https://xxxx/error","g");
				if (regexp.test(options.url)) {
				    //这里要执行原来的方法
					return originRequest.call(this, options)
				}
				//这里拦截请求成功或失败接口,拿到请求后的数据
				["success", "fail"].forEach((methodName) => {
					let defineMethod = options[methodName];
					options[methodName] = function(){
						try{	      //在重新定义函数中执行原先的函数,不影响正常逻辑
						    defineMethod && defineMethod.apply(this, arguments);
						    //开始信息收集
							let statusCode, result, msg;
							//请求失败
							if (methodName == 'fail') {
								statusCode = 0;
								result = 'fail';
								msg = ( arguments[0] && arguments[0].errMsg ) || ""
							}
							//请求成功,
							//收集规则为:
							// 1、 statusCode非2xx,3xx
							// 2、 statusCode是2xx,3xx,但接口返回result不为ok
							if (methodName == 'success') {
								let data = arguments[0] || {};
								statusCode = data.statusCode || "";
								if (data.statusCode && Number(data.statusCode) >= 200 && Number(data.statusCode) < 400 ) {
									let resData = data.data ? (typeof data.data == 'object' ? data.data : JSON.parse(data.data)) : {};
									//请求成功,不收集
									if (resData.result == 'ok') {
										return;
									}
									result = resData.result || "";
									msg = resData.msg || "";
								}else{
									result = "";
									msg = data.data || "";
								}
							}
							//过滤掉header中的敏感信息
							if (options.header) {	
								options.header.userid && (delete options.header.userid)
							}
							//过滤掉data中的敏感信息
							if (options.data) {	
								options.data.userid && (delete options.data.userid)
							}
							
					        var collectInfo = {
								"url": options.url || '',	//请求地址
								"method": options.method || "GET",	//请求方法
								"request_header": JSON.stringify(options.header || {}), //请求头部信息
								"request_data": JSON.stringify(options.data || {}), //请求参数
								"resp_code": statusCode + '',	//请求状态码
								"resp_result": result, //请求返回结果
								"resp_msg": msg, //请求返回描述信息
					        }
					        //提交参数与上一次不同,或者参数相同,隔了1s
					        if (JSON.stringify(collectInfo) != lastParams.paramStr || (new Date().getTime() - lastParams.timestamp > 1000)) {
					        	//上传错误信息
					        	Post.post_error(_miniapp, 'http', collectInfo)
					        	lastParams.paramStr = JSON.stringify(collectInfo);
					        	lastParams.timestamp = new Date().getTime()
					        }

						}catch(e){
							//console.log(e);
						}
					};	
				})
			  	return originRequest.call(this, options)
			}
		})
	} catch (e) {
		// Do something when catch error
	}
}

В апплете, который не использует плагины, мы можем использовать метод wx.request для выполнения приведенного выше кода, перехвата wx.request, а затем сбора http-запросов без добавления кода. Как было сказано выше, когда мы инкапсулируем его в плагин, это не работает, потому что при использовании плагина апплет не позволяет нам модифицировать глобальные переменные. Поэтому, когда приведенный выше код будет выполнен, будет сообщено об ошибке. На данный момент мы должны согласиться на следующий лучший вариант.Мы можем только инкапсулировать метод в плагине.Этот метод на самом деле является wx.request для отправки запроса, но в плагине мы можем перехватить wx. запрос. Конкретная реализация выглядит следующим образом:

    function my_request(){
        //只要执行一次拦截代码即可
        !_isInit && rewriteRequest();
        return  wx.request(options)
    }

Далее, давайте посмотрим на фоновые данные

Непрерывный мониторинг поможет нам найти множество скрытых ошибок

4 Резюме


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