如何在React Native中实现执行时间长的代码?

时间:2019-08-22 05:25:32

标签: javascript react-native expo

我正在使用React Native和Expo构建一个新的应用程序。 这个程序的主要功能是为用户生成计划。 生成算法大约需要300-500秒才能执行。 (它最多包含2,100,000次随机生成。)

当前我面临两个问题:

第1季度。在测试过程中,这段代码直接放在App.js-App类-渲染函数中。但是,如果执行时间超过32秒,则该应用将无法呈现,并且永远保持无响应。

所以问题是:

1.1 是最长32秒否则没有响应的原因是什么?

1.2 有更好的测试方法吗?

当前测试方法:

export default class App extends React.Component {
  componentDidMount() {
    if (__DEV__) {
      Reactotron.connect();
      Reactotron.log('hello rendering world');
    }
  }

  render() {
    //test
    generatePlan(store.getState(), 0);

    return (
      <Provider store={store}>
        <AppContainer />
      </Provider>
    );
  }
}

第二季度。,在单击“生成”按钮后,不可能让用户长时间保持呆呆状态。因此,理想情况下,此长时间执行的任务应在资源有限(包括内存和计算)的后台运行,以便用户可以在等待期间执行其他操作而不会受到太大影响(例如病毒扫描任务,一旦完成,就会弹出)消息等)

所以这里的问题是:

如何实现?

我尝试过的事情:

对于第一季度: 目前,我不知道原因,甚至无法找出要搜索的准确关键词。 (我尝试在Google中搜索“反应本机执行时间长”,“无响应”等,以响应本机github问题,世博论坛,但没有运气。)

目前,我进行测试的想法是分别执行每个部分并手动存储每个部分的结果。然后使用每个部分的存储结果完成最后一部分。

第二季度: 有一个库“ react-native-background-task”:

“该库允许调度单个定期任务,该任务在应用程序处于后台或关闭状态时执行,执行频率不超过每15分钟一次。可以使用网络,AsyncStorage等(UI以外的任何方式),因此非常完美用于后台数据同步以提供脱机支持。”

但是关于此潜在解决方案有两个问题:

a。:打开应用程序后如何在后台运行任务?

b。。如何限制此任务使用的计算资源? (因为任务可以缓慢执行,但是如果用户仍在使用手机,则不应占用太多计算资源。)

2 个答案:

答案 0 :(得分:1)

好吧,我不认为您的问题有一个明确的答案,但这就是我的想法:

  • 我不确定约32秒的渲染限制,但是将UI阻塞1秒钟是不切实际的,并且对用户体验不利。
  • var ids = [1, 4, 4, 4, 5, 6, 6]; var distinctIds = ids.toSet().toList(); 方法内执行任何操作不是一个好习惯。每当更新状态或重新渲染组件时,都会频繁调用此方法。因此,它应该尽可能轻巧,并且只应包含返回的组件。另外,为了避免任何意外行为,render()方法应为pure method
  • 在这种情况下,我要做的是用C ++重写计算算法,然后在React Native和Android / iOS之间建立一座桥梁,在那里我可以在UI线程旁边的线程上运行代码,然后将值返回给JavaScript应用的一部分。
    • 在繁重的计算中使用C ++可以提高性能,并且可以帮助您将算法保持在一个位置(以简化维护和调试工作)。
    • 您还可以使用Java / Kotlin(适用于Android)和Objective-C(适用于iOS)编写该算法两次,此方法可避免任何C ++代码复杂化,但是再次用相同的语言编写相同的代码两次(因此,会面临其他并发症)。
    • 查看此article,以了解有关本机模块/桥的更多信息。
    • 也请查看此article以获得有关Android版C ++的信息。
  • 解决此问题的另一种方法是将算法移动到集中式服务器,在该服务器上计算值并将其存储在服务器上,然后使用某种Web API对其进行检索。
  • 现在,如果您(出于某种原因)希望将算法保留在JavaScript中,则必须将计算过程分解为细小且轻巧的部分,然后每部分都render(),例如,如果您的算法生成了一个随机数并对其进行一些计算,然后重复此过程2百万次。每次计算都需要requestAnimationFrame,将当前结果存储在某个位置,并请求另一帧进行下一次计算。
    • 之所以要这样做,是因为根据合同,JavaScript只有一个线程,并且所有JS代码(包括屏幕上的渲染框架)都在该线程上发生,因此我们将代码分成小段,以允许在它们之间呈现新的帧。
    • 查看此article,了解有关划分工作负载和动画帧的更多信息。

祝你好运

答案 1 :(得分:0)

@Heysem Katibi非常感谢您对此发表看法。

以下是我在解决此问题的过程中的发现和经验。

  1. React Native的Javascript部分最初是单线程的(当前是2019年10月),这意味着任何长时间执行的代码都会直接阻止主UI线程。
  2. 对于长执行代码,确实有多种解决方案来避免此阻塞问题。但是,目前使用Expo(或不弹出/分离)都无法实现这些目标。

详细的解决方案:

  1. 反应本机Javascript工作者:react-native-threads(本身或与hamsters.js配合使用,以进一步加快速度)。

    react-native-threads将在主UI JavaScript进程之外产生新的React Native JavaScript进程,以进行CPU密集型工作。

    hamsters.js是一个Javascript多线程和并行执行库,可以在需要带有React Native的工作程序库(例如:react-native-threads)时进一步提高执行速度。

  2. requestAnimationFrame :将代码分成多个部分,并在每个框架中执行。

    请参见Intensive JavaScript。 这可能行得通,但是,如本文所示,性能将不如worker。

  3. 转到本机代码

    • iOS的Objective-C / Swift和android的Java / Kotlin
    • 两个平台的
    • C ++。 但是,这需要编译用于移动设备的所有C ++库(有时可能会很复杂,例如:google / or-tools既不提供官方的移动编译版本,也没有提供官方指南)。
    • 适用于平台的Golang,并使用golang/mobile进行iOS和Android编译。 但是,Golang当前(2019年)没有成熟的生态系统。因此很难获得第三方软件包。
    • 此外,可能还有其他一些语言为iOS和android提供捆绑。

    在任何情况下,将代码移至本机都可能会提高执行速度。

  4. 移至服务器端: 使用远程服务器来完成繁重的工作,而移动端只是请求结果。而且,这可以与上述解决方案一起使用(考虑使用相同的语言编写代码并在移动端和服务器端复用)。

感谢原始海报。

P.S:我刚刚发现在React Native项目中加密javascript代码非常困难。因此,建议不要在javascript中甚至前端放置任何敏感代码。