Optimizing JavaScript loading
解析和运行 JavaScript 代码需要内存和时间。因此,随着你的应用程序增长,通常将代码加载延迟到首次需要时是有用的。React Native 自带一些默认开启的标准优化,并且你可以在自己的代码中采用一些技术来帮助 React 更有效地加载你的应用程序。还有一些适合非常大应用程序的高级自动优化(它们也有自己的权衡)。
推荐:使用 Hermes
Hermes 是新 React Native 应用的默认引擎,它对高效代码加载进行了高度优化。在发布版本中,JavaScript 代码会完全提前编译成字节码。字节码按需加载到内存中,并不需要像普通 JavaScript 那样进行解析。
推荐:延迟加载大型组件
如果一个包含大量代码/依赖项的组件在最初渲染应用程序时不太可能被使用,您可以使用 React 的 lazy
API 来推迟加载其代码,直到它首次呈现。通常,您应该考虑延迟加载应用程序中的屏幕级组件,这样添加新屏幕到您的应用程序就不会增加其启动时间。
阅读更多关于 带有 Suspense 的延迟加载组件 的信息,包括代码示例,在 React 文档中。
小贴士:避免模块副作用
如果组件模块(或其依赖项)具有副作用,例如修改全局变量或在组件外部订阅事件,则延迟加载组件可能会改变应用程序的行为。React 应用中的大多数模块都不应有任何副作用。
import Logger from './utils/Logger';
// 🚩 🚩 🚩 副作用!这必须在 React 开始渲染 SplashScreen 组件之前执行,
// 如果你决定延迟加载 SplashScreen,它可能会意外地破坏应用中其他地方的代码。(比如需要依赖logger的代码)
global.logger = new Logger();
export function SplashScreen() {
// ...
}
高级:内联调用 require
有时,您可能希望将一些代码的加载推迟到第一次使用时,而不是使用 lazy
或异步的 import()
。您可以通过在文件顶部本来会静态使用 import
的地方,改用 require()
函数来实现这一点。
import {Component} from 'react';
import {Text} from 'react-native';
// ... import 一些开销非常大的模块
export default function VeryExpensive() {
// ... 开销非常大的渲染逻辑
return <Text>Very Expensive Component</Text>;
}
import {useCallback, useState} from 'react';
import {TouchableOpacity, View, Text} from 'react-native';
// 一般我们会静态导入某个组件
// import VeryExpensive from './VeryExpensive';
// 但由于这个组件开销非常大,这里我们可以改用 require
let VeryExpensive = null;
export default function Optimize() {
const [needsExpensive, setNeedsExpensive] = useState(false);
const didPress = useCallback(() => {
if (VeryExpensive == null) {
VeryExpensive = require('./VeryExpensive').default;
}
setNeedsExpensive(true);
}, []);
return (
<View style={{marginTop: 20}}>
<TouchableOpacity onPress={didPress}>
<Text>Load</Text>
</TouchableOpacity>
{needsExpensive ? <VeryExpensive /> : null}
</View>
);
}
高级:自动内联 require
调用
如果您使用 React Native CLI 构建您的应用程序,require
调用(但不是 import
)将会自动为您内联,这既适用于您的代码,也适用于您使用的任何第三方包(node_modules
)。
import {useCallback, useState} from 'react';
import {TouchableOpacity, View, Text} from 'react-native';
// This top-level require call will be evaluated lazily as part of the component below.
const VeryExpensive = require('./VeryExpensive').default;
export default function Optimize() {
const [needsExpensive, setNeedsExpensive] = useState(false);
const didPress = useCallback(() => {
setNeedsExpensive(true);
}, []);
return (
<View style={{marginTop: 20}}>
<TouchableOpacity onPress={didPress}>
<Text>Load</Text>
</TouchableOpacity>
{needsExpensive ? <VeryExpensive /> : null}
</View>
);
}
一些 React Native 框架禁用了这种行为。例如在 Expo 项目中,默认情况下不会内联 require
调用。你可以通过编辑项目的 Metro 配置,并在 getTransformOptions
中设置 inlineRequires: true
来启用此优化。