如何更快地使React Native移动应用程序?

时间:2018-03-26 13:02:03

标签: android performance react-native redux stack-trace

React Native移动应用程序在每次点击时工作都很慢。 我正在使用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点击需要更多时间的原因之一。您可以查看stacktrace报告here

有人可以帮我解决这个性能问题。?

5 个答案:

答案 0 :(得分:5)

首先,您应该在 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动画和处理程序(例如onScrollonPress,当然{ {1}}方法)受此影响。尝试仅加载您需要显示的内容。
  2. 尽可能使用原生动画(render参数),尽量不要使用useNativeDriver: true
  3. 记录所有onScroll方法,并尝试尽可能少地调用这些方法。当组件的道具或状态发生变化时调用它。
  4. 了解render的工作原理并尝试在必要时使用它。但请记住,如果使用不当,它也会降低应用程序的速度。
  5. 始终对样式使用PureComponent,它会兑换它们并替换为样式ID(整数)。
  6. 为:

    StyleSheet

    好:

    // style object is created on every render
    render() {
        return <View style={{flex:1}}/>
    }
    
    1. 与功能相同。
    2. 为:

      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')}/>
      }
      
        客户端上所有操作的
      1. Big O应该是不变的。尽可能少地枚举数组。始终尽可能使用render() { <TouchableOpacity onPress={this.onPressSignIn}/> } // onPressSignIn is created once onPressSignIn = () => { this.props.navigator.navigate('SignIn'); } Object代替Set。当您需要从服务器/数据库加载大量数据时,请使用分页,为服务器留下排序和其他繁重的计算。
      2. 例如,如果您经常需要通过id获取对象,最好使用:

        Array

        而不是通常的数组:

        let items = {
            "123": { id: "123", ... },
            "224": { id: "224", ... }
        };
        
        let item = items["123"];
        

答案 1 :(得分:4)

这是一个非常广泛基于意见的问题,但我会尝试突出显示基于most common points的{​​{1}}和建议你已经列出了。

查看堆栈跟踪,主要问题在于包名称中的profiler,即UI Thread

如上所述here

  

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

一旦边界间隔设置为com.fitspot.app.debug,您就可以看到16msmqt_js在一个周期内花费的时间远远超过JS Thread,这意味着16ms一直在运行。

在当前JS Thread中,不清楚profiler中执行了哪些流程,因此很明显问题主要在于您的JS Thread,而不是JS Code }。

有多种方法可以加快UI Thread应用的速度,这在page中有详细记录。这是一个基本要点。

  • 错误和警告消息在react-native模式下提供,您可以在整个应用中停用它们,以获得更好的效果。
  • 从您的应用中删除所有dev=true语句,因为它会在JS主题上导致bottleneck。您可以使用此插件删除.babelrc文件中提到的所有console.log语句here

    console*
  • 您需要{ "env": { "production": { "plugins": ["transform-remove-console"] } } } 项目结构,并使用componentize,仅依靠Pure Componentsprops,更快地使用state比较。

  • 对于immutable data structures,您可能需要检查slower navigation transitions代码,因为他们大多数navigation library代表timeout。作为解决方法,您可以考虑构建自己的default transitions

  • 如果您在代码库中使用transitioner,则可以考虑设置Animations,这会减少nativeDriver=true的负担。这里有一个很好的解释example

  • 您还可以查看分析,查看JS threadJS Thead操作,在此页面上有详细说明。

    < / LI>
  • 其他内容包括,不是Main Thread模块,这不是必需的,仅导入所需的requiring/importing,而不是classes

  • 此外,您不需要whole component制作external libraries,因为它们的效果比simple UI components的原生元素要慢得多。您可以考虑使用styled-components对您的react-native

  • 进行组件化

答案 2 :(得分:3)

  1. 在Scrollview上使用Flatlist

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

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

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

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

答案 3 :(得分:2)

可能有各种原因导致本机反应速度变慢。我建议以下关键点可以提供帮助:

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

答案 4 :(得分:1)

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

Pritish Vaidya给出的Answer已经击中了头部。我只想在您的应用中再添加一点关于redux的使用情况。如果您的应用的数据流主要使用redux完成,那么您可以检查以下内容:

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

  • 将听取redux存储的组件分成较小的组件,每个组件都会监​​听存储的不同部分。因此,如果更新redux的商店,则只应重新呈现一小部分组件而不是一切。

  • 使用记忆选择器处理经常更新的数据。在这种情况下,reselect可以为您提供帮助。