Как ускорить работу мобильного приложения React?
React Native mobile приложение работает очень медленно при каждом нажатии. Я использую v0.40.0
native v0.40.0
и следую за зависимостями моего проекта.
{
"analytics-react-native": "^1.1.0",
"apisauce": "^0.7.0",
"babel-preset-es2015": "^6.18.0",
"es6-promise": "^4.0.5",
"flow-bin": "^0.36.0",
"geolib": "^2.0.22",
"immutable": "^3.8.1",
"intl": "^1.2.5",
"isomorphic-fetch": "^2.2.1",
"lodash": "^4.17.4",
"lodash.range": "^3.2.0",
"prop-types": "^15.5.10",
"raven-js": "^3.13.1",
"react": "^15.4.2",
"react-native": "^0.40.0",
"react-native-apple-healthkit-rn0.40": "^0.3.2",
"react-native-blur": "^2.0.0",
"react-native-button": "^1.7.1",
"react-native-checkbox": "^2.0.0",
"react-native-code-push": "^1.17.3-beta",
"react-native-datepicker": "^1.4.4",
"react-native-device-info": "^0.10.1",
"react-native-easy-toast": "^1.0.6",
"react-native-fbsdk": "^0.5.0",
"react-native-geocoder": "^0.4.5",
"react-native-gifted-chat": "^0.1.3",
"react-native-global-props": "^1.1.1",
"react-native-image-crop-picker": "^0.15.1",
"react-native-image-picker": "^0.25.1",
"react-native-image-slider": "^1.1.5",
"react-native-keyboard-aware-scroll-view": "^0.2.7",
"react-native-maps": "0.15.2",
"react-native-modal-dropdown": "^0.4.4",
"react-native-popup-menu": "^0.7.2",
"react-native-push-notification": "^2.2.1",
"react-native-radio-buttons": "^0.14.0",
"react-native-router-flux": "3.38.0",
"react-native-segmented-android": "^1.0.4",
"react-native-snap-carousel": "2.1.4",
"react-native-stars": "^1.1.0",
"react-native-swipeout": "^2.2.2",
"react-native-swiper": "^1.5.4",
"react-native-tableview-simple": "0.16.5",
"react-native-vector-icons": "^4.0.0",
"react-native-video": "^1.0.0",
"react-native-zendesk-chat": "^0.2.1",
"react-redux": "^4.4.6",
"recompose": "^0.20.2",
"redux": "^3.5.2",
"redux-thunk": "^2.0.1"
}
Я сделал профилирование с помощью stacktrace в андроид-студиях и обнаружил, что mqt_js является одной из причин, которая занимает больше времени на каждом клике пользовательского интерфейса. Вы можете проверить отчет stacktrace здесь
Может ли кто-нибудь помочь мне в решении этой проблемы производительности?
Ответы
Ответ 1
Это очень широкий и основанный на мнениях вопрос, но я попытаюсь выделить most common points
и предложения, основанные на profiler
вы указали.
Рассматривая трассировку стека, основная проблема заключается в com.fitspot.app.debug
UI Thread
внутри вашего имени пакета, то есть com.fitspot.app.debug
.
Как уже упоминалось здесь.
для того, чтобы отобразить рамку, все наши работы с пользовательским интерфейсом должны быть выполнены к концу этого 16 мс периода.
Как только граничный интервал установлен на 16 16ms
, вы увидите, что mqt_js
или mqt_js
JS Thread
занимают намного больше 16 16ms
за один цикл, то есть ваш 16ms
JS Thread
работает постоянно.
В текущем profiler
неясно, какие процессы выполняются в вашем JS Thread
, поэтому ясно, что проблема заключается главным образом в вашем JS Code
а не в UI Thread
.
Существует несколько способов ускорить работу react-native
приложения, которое хорошо документировано на этой странице. Здесь основной смысл в том же.
- Сообщения об ошибках и предупреждения предоставляются в режиме
dev=true
, вы можете отключить их в приложении для повышения производительности. -
Удалите все инструкции console.log
из вашего приложения, поскольку это вызывает bottleneck
в потоке JS. Вы можете использовать этот плагин для удаления всех команд console*
как указано здесь, в ваших.babelrc файлах как
{
"env": {
"production": {
"plugins": ["transform-remove-console"]
}
}
}
-
Вам необходимо componentize
структуру вашего проекта и использовать Pure Components
, чтобы полагаться только на props
и state
, используйте immutable data structures
для более быстрого сравнения.
-
Для slower navigation transitions
вам может потребоваться проверить код navigation library
, поскольку в большинстве случаев у них есть timeout
для default transitions
по default transitions
. В качестве обходного пути вы можете подумать о создании своего собственного transitioner
.
-
Если вы используете Animations
в своей кодовой базе, вы можете nativeDriver=true
установить nativeDriver=true
, что уменьшит нагрузку на ваш JS thread
. Вот хорошо объясненный пример.
-
Вы также можете проверить профилирование, проверить действия JS Thead
и Main Thread
, хорошо объясненные на этой странице.
-
Другие вещи включают, не requiring/importing
модуль, который не нужен, импортируя только требуемые classes
, а не whole component
.
-
Кроме того, вам не нужны external libraries
чтобы создавать simple UI components
, так как их производительность намного медленнее, чем собственные элементы react-native
. Вы можете рассмотреть использование styled-components
для компонентного UI
Ответ 2
Прежде всего, вы должны запускать свое приложение не в DEBUG. На MainApplication
это делается путем изменения метода MainApplication
:
@Override
public boolean getUseDeveloperSupport() {
return false; // BuildConfig.DEBUG;
}
и создание пучка:
react-native bundle --platform android --dev false --entry-file ./index.js --bundle-output ./android/app/src/main/assets/index.android.bundle --assets-dest ./android/app/src/main/res/ --sourcemap-output ./android/app/src/main/assets/index.android.map
Что касается кода, вот несколько советов по оптимизации реагирования:
- Анализ и сериализация (например,
response.json()
или JSON.stringify
) блокирует поток js, поэтому все анимации и обработчики JS (такие как onScroll
и onPress
, и, конечно, метод render
) страдают от этого. Попробуйте загрузить только то, что вам нужно показать. - Используйте собственные анимации (
useNativeDriver: true
параметр), где это возможно, и старайтесь не использовать onScroll
. - Запишите все ваши методы
render
и попытайтесь сделать так, чтобы вызов этих методов был как можно редок. Он вызывается при изменении компонентов или состояния компонентов. - Понимать, как работает
PureComponent
и пытаться использовать его там, где это необходимо. Но имейте в виду, что это также может замедлить приложение вниз, если оно не используется правильно. - Всегда используйте
StyleSheet
для стилей, он использует их и заменяет идентификатором стиля (integer).
Плохой:
// style object is created on every render
render() {
return <View style={{flex:1}}/>
}
Хорошо:
render() {
<View style={styles.flex}/>
}
// style is created once
const styles = StyleSheet.create({
flex: { flex: 1 }
});
- То же самое с функциями.
Плохой:
// onPress handler is created on every render
render() {
<TouchableOpacity onPress={() => this.props.navigator.navigate('SignIn')}/>
}
Хорошо:
render() {
<TouchableOpacity onPress={this.onPressSignIn}/>
}
// onPressSignIn is created once
onPressSignIn = () => {
this.props.navigator.navigate('SignIn');
}
- Большая O всех операций с клиентом должна быть постоянной. Перечислите массивы как можно меньше. Всегда используйте
Object
и Set
вместо Array
где это возможно. Используйте разбивку на страницы, когда вам нужно загружать большие объемы данных с сервера/базы данных, сортировать сообщения и другие тяжелые вычисления для сервера.
Например, если вам часто нужно получать объекты по id, лучше использовать:
let items = {
"123": { id: "123", ... },
"224": { id: "224", ... }
};
let item = items["123"];
вместо обычного массива:
let items = [
0: { id: "123", ... },
1: { id: "224", ... }
];
let item = items.find(x => x.id === "123");
Ответ 3
-
Используйте Flatlist над Scrollview:
- добавьте
initialNumToRender={number}
prop в Flatlist, так как он отобразит только те компоненты, которые видны на экране, и отсоедините другие компоненты
-
Используйте PureComponent в Flatlist renderItem (в вашем случае это будет каждая карта), так что они будут отображаться только при изменении их реквизита.
-
Проверьте, повторяет ли ваш компонент повторно и снова, чтобы проверить консоль пуста либо в render(), либо в ComponentWillRecieveProps, и если это происходит, используйте функцию ShouldComponentUpdate.
-
Удалите console.log из render() и ComponentWillRecieveProps.
Внесите эти изменения, и вы увидите, что ваша производительность намного лучше, чем раньше.
Ответ 4
Могут быть разные причины, из-за которых приложение, реагирующее на взаимодействие, замедляется. Я бы предложил следующие ключевые моменты, которые могут помочь:
- Предпочитайте
dumb components
над class components
где это возможно. - Попробуйте использовать
redux
, это мощный инструмент управления государством, который может предоставить вам лучший код, если он будет реализован должным образом. - Используйте инструменты, такие как
react-monocole
и appr
. Руководство по реакции-моноколу. - Сгенерируйте подписанный apk, отлаженное приложение для реагирования имеет дополнительные функции. Вот руководство для генерации подписанного apk.
Ответ 5
Если mqt_js
является основной причиной проблемы с производительностью, это означает, что в каждом клике поток JS вашего приложения имеет слишком много вещей, чтобы сделать это сразу. Коммуникация между бизнес-логикой JS и базой подчиненной области выполняется асинхронно, чем больше действий нужно закончить на стороне JS при нажатии кнопки, тем медленнее будет приложение.
Ответ, данный Притиш Вайдя, уже попадает в гвоздь по голове. Я просто хочу добавить еще 1 пункт об использовании redux
в приложении. Если поток данных ваших приложений в основном выполняется с помощью redux
вы можете проверить следующие вещи:
-
Если в каждом клик-событии происходит слишком много действий сокращения, попробуйте удалить ненужные или приоритизировать действия, запускающие важные анимации, а затем вызывать другие действия после завершения рендеринга новых компонентов RN. Вы можете видеть, какие действия являются нижестоящими из-за redux-logger
.
-
Компоненты Break, которые слушают редукцию, хранятся в меньших, каждый из которых прослушивает другую часть магазина. Поэтому, если обновление магазина сокращено, только небольшая группа компонентов должна быть перезаписана вместо всего.
-
Используйте memoized selectors для работы с часто обновляемыми данными. reselect может помочь вам в этом случае.