问题 如何更快地使React 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"
  }

我在android工作室中使用stacktrace进行了分析,发现mqt_js是每次UI点击需要更多时间的原因之一。您可以查看堆栈跟踪报告 这里 

任何人都可以帮助我解决这个性能问题。


2805
2018-03-26 13:02


起源

这些延迟是否发生在您的应用的生产版本中?或者只是开发构建?你尝试过使用类似的东西吗? redux-logger 看到你被解雇的所有行为? - Dan
它在生产和开发建设方面都有所延误。我已经在使用了 redux-logger。 - Kishan Vaghela
尝试在IOS上使用systrace,它可能会显示一些内容。从附加的跟踪(android),在UI线程(所有绿色F)中看不到帧丢失,但是在点击后JS线程(mqt_js)中似乎有很多工作正在进行。 unfortuantely systrace在android上被打破,以提供JS线程的细节。如果可以的话,附上ios systrace。 - jay shah


答案:


这是非常的 广阔 和 意见为基础 问题,但我会尽力突出 most common points 和基于的建议 profiler 你已经列出了。

看看你的堆栈跟踪,主要问题在于 UI Thread 在你的包名内,即 com.fitspot.app.debug

如上所述 这里

为了显示一个框架,我们所有的UI工作都需要在16ms周期结束时完成。

一旦边界间隔设置为 16ms那么你可以看到了 mqt_js 或者 JS Thread 花的时间远远超过 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。作为一种解决方法,您可以考虑建立自己的 transitioner

  • 如果你正在使用 Animations 在您的代码库中,您可以考虑设置 nativeDriver=true,这将减少你的负担 JS thread。这是一个很好的解释

  • 您也可以查看 剖析,检查一下 JS Thead 和 Main Thread 操作,在此页面上有很好的解释。

  • 其他东西包括,不是 requiring/importing 模块,这是不必要的,仅导入 classes 要求,而不是 whole component

  • 另外,你不需要 external libraries 制作 simple UI components,因为他们的表现比原生元素慢得多 react-native。你可以考虑使用 styled-components 组件化你的 UI


4
2018-03-29 11:00





首先,你应该运行你的应用程序 DEBUG。在Android上它是通过改变来完成的 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

至于代码,这里有一些优化react-native的建议:

  1. 解析和序列化(例如 response.json() 要么 JSON.stringify)阻塞js线程,所以所有JS动画和处理程序(如 onScroll 和 onPress, 而且当然 render 方法)受此影响。尝试仅加载您需要显示的内容。
  2. 使用原生动画(useNativeDriver: true 参数)尽可能,并尽量不使用 onScroll
  3. 记录所有你的 render 方法并尝试尽可能少地调用这些方法。当组件的道具或状态发生变化时调用它。
  4. 了解如何 PureComponent 工作,并尝试在必要时使用它。但请记住,如果使用不当,它也会降低应用程序速度。
  5. 一直用 StyleSheet 对于样式,它会兑换它们并替换为样式id(整数)。

坏:

// 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 }
});
  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');
}
  1. 大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");

4
2018-04-02 17:36





  1. 使用 Flatlist 在Scrollview上:

    • initialNumToRender={number} 支持Flatlist,因为它只显示屏幕上可见的组件并分离其他组件
  2. 使用 PureComponent 在Flatlist中呈现renderItem(在你的情况下它将是每张Card),这样它们只会在它们的道具被改变时呈现。

  3. 检查您的组件是否一次又一次地重新渲染,以便在render()或ComponentWillRecieveProps中测试put控制台,如果发生这种情况,则使用ShouldComponentUpdate。

  4. 从render()和ComponentWillRecieveProps中删除console.log。

进行这些更改,您会发现您的表现比以前好多了。


3
2018-03-26 15:35





可能有各种原因使反应原生应用程序变慢。我建议以下关键点可以提供帮助:

  1. 比较喜欢 dumb components 过度 class components 尽可能。
  2. 尝试使用 redux,它是一个功能强大的状态管理工具,如果正确实施,可以为您提供最佳代码。
  3. 使用像 react-monocole 和 appr。指南 反应-monocole
  4. 生成已签名的apk,已调试的react-native应用程序中包含其他功能。这是一个指南 生成签名的apk

2
2018-03-31 05:31



愚蠢的组件如何工作? - Kishan Vaghela
请按照本指南操作 medium.com/@thejasonfile/... - madhav gaba


如果 mqt_js 是性能问题的主要原因,这意味着在每次点击时,您的应用程序的JS线程都有很多事情要做。 JS业务逻辑和底层本机领域之间的通信是异步完成的,当按下按钮时需要在JS端完成的操作越多,应用程序就越慢。

回答 由Pritish Vaidya给出的已经击中头部的钉子。我只想再提一点关于使用的问题 redux 在你的应用程序中如果您的应用程序的数据流主要使用完成 redux那么你可以检查以下事项:

  • 如果每次点击事件都发生了太多的redux动作,请尝试删除不必要的动作,或者先确定触发重要动画的动作的优先级,然后在新的RN组件完成渲染后触发其他动作。你可以看到哪些动作是最底层的 redux-logger

  • 将侦听redux存储的组件分解为较小的组件,每个组件都监听存储的不同部分。因此,如果更新redux的存储,则只应重新呈现一小组组件而不是所有组件。

  • 使用memoized选择器来处理经常更新的数据。 重新选择 在这种情况下可以帮助你。


1
2018-04-04 08:55