React Native-处理沉重JS代码而又不影响性能/渲染的最佳方法

时间:2018-12-16 18:13:52

标签: javascript reactjs react-native webview

我一直在研究React native中的一些特定用例,在这里我想执行一些繁重的JS操作,而不会干扰在react native中运行UI和动画的主线程。

例如,一旦安装了应用程序组件或用户触发了任何动画序列(例如,导航到新视图动画,打开一些详细信息页面动画等),就会立即运行for循环10K次。

如果我在动画开始之前执行以下代码,

// animate the item details page (from item list page)
onItemPressed() {
// Some JS code to mimic heavy processing
console.log('starting...');
for (let i = 0; i < 5000; i++) {
  (Math.random() * 9999999) / 7;         
}
console.log('Finished');

// starting animation sequence
this.setState({animationPhase: 'phase-2'});
}

直接运行上面的代码后,由于动画在动画开始之前运行,因此动画比较迟钝。

我正在研究以下方法:

  1. 使用RN的InteractionManager-阅读文档后,可以按照docs中所述实现它-将for循环包装在InteractionManager.runAfterInteractions()处理函数中。但是,这不能完全解决问题。它下面还有另一种称为 setDeadline 的方法,该方法的文献资料很少。我认为它对于处理数据块而不是一次处理整个代码很有用。不确定如何使用它。

  2. RequestAnimationFrame / SetTimeout-无法按预期工作

  3. 反应本机线程/工作者-Web工作者(如API)在后台处理任务。这可以正常工作,并具有额外的优势,即我们可以向工作线程发送消息/从工作线程监听消息,以开始/停止任务执行。根据{{​​3}}的文档,我们可以将其用作-

    import { Thread } from 'react-native-threads'; // import it in the required component
    
    this.thread = new Thread('./JS_FILE_THAT_HAS_HEAVY_DUTY_CODE.js'); // create new instance of it
    
    this.thread.onmessage = (message) => {} // listen to messages coming from the JS file
    
    this.thread.postMessage('Start'); // post message to the thread
    
    
    componentWillUnmount() {
        // stop the JS process
        this.thread.terminate();
     }
    
    // In thread.js file,
    
    import { self } from 'react-native-threads'; // import current worker context obj
    
    self.onmessage = message => {    // Listen to messages coming from parent script
    
       // start execution
    
    }
    
    self.postMessage('Completed');  // post messages to parent script
    
  4. 使用WebView-我还没有尝试过,但是RNThreads在这种情况下似乎很有用,但是将字符串化的javascript注入到Web视图中可以吗?不确定。

我的问题是-

  1. 我想进一步了解RN Interaction Manager,尤其是setDeadline()方法-如何使用它以及它做什么。
  2. 在这种用例中哪种方法更好?

1 个答案:

答案 0 :(得分:1)

由于您对InteractionManager.setDeadline()不太熟悉,因此我对您没有可靠的答案,但是我认为看看测试可以为您提供所需的见解。通常,测试可以作为缺少文档的很好的替代品。

因此,请看一下InteractionManager-test.js, specifically L230-L261

在那里,您会找到这些测试...

it('should execute tasks in loop within deadline', () => {
    InteractionManager.setDeadline(100);
    BatchedBridge.getEventLoopRunningTime.mockReturnValue(10);
    const task1 = createSequenceTask(1);
    const task2 = createSequenceTask(2);
    InteractionManager.runAfterInteractions(task1);
    InteractionManager.runAfterInteractions(task2);

    jest.runOnlyPendingTimers();

    expectToBeCalledOnce(task1);
    expectToBeCalledOnce(task2);
  });

  it('should execute tasks one at a time if deadline exceeded', () => {
    InteractionManager.setDeadline(100);
    BatchedBridge.getEventLoopRunningTime.mockReturnValue(200);
    const task1 = createSequenceTask(1);
    const task2 = createSequenceTask(2);
    InteractionManager.runAfterInteractions(task1);
    InteractionManager.runAfterInteractions(task2);

    jest.runOnlyPendingTimers();

    expectToBeCalledOnce(task1);
    expect(task2).not.toBeCalled();

    jest.runOnlyPendingTimers(); // resolve1
    jest.runOnlyPendingTimers(); // task2

    expectToBeCalledOnce(task2);
});

在我看来,这是一种划分工作的方法,这可能会很有用。

您的解决方案3.很有趣。我个人很希望看到一些与此相关的代码。我没有这方面的经验,但这听起来令人兴奋。我认为Webview无疑应该有助于将工作卸载到单独的线程中,但是我以前从未在这种情况下使用过它。