我一直在研究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'});
}
直接运行上面的代码后,由于动画在动画开始之前运行,因此动画比较迟钝。
我正在研究以下方法:
使用RN的InteractionManager-阅读文档后,可以按照docs中所述实现它-将for循环包装在InteractionManager.runAfterInteractions()处理函数中。但是,这不能完全解决问题。它下面还有另一种称为 setDeadline 的方法,该方法的文献资料很少。我认为它对于处理数据块而不是一次处理整个代码很有用。不确定如何使用它。
RequestAnimationFrame / SetTimeout-无法按预期工作
反应本机线程/工作者-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
使用WebView-我还没有尝试过,但是RNThreads在这种情况下似乎很有用,但是将字符串化的javascript注入到Web视图中可以吗?不确定。
我的问题是-
答案 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无疑应该有助于将工作卸载到单独的线程中,但是我以前从未在这种情况下使用过它。