Saltar al contenido principal
Versión: 0.81

Optimización de la carga de JavaScript

Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

Analizar y ejecutar código JavaScript requiere memoria y tiempo. Por este motivo, a medida que tu aplicación crece, suele ser útil retrasar la carga del código hasta que se necesite por primera vez. React Native incluye algunas optimizaciones estándar activadas por defecto, y existen técnicas que puedes implementar en tu propio código para ayudar a React a cargar tu aplicación de manera más eficiente. También hay optimizaciones automáticas avanzadas (con sus propias contrapartidas) adecuadas para aplicaciones muy grandes.

Recomendado: Usa Hermes

Hermes es el motor predeterminado para nuevas aplicaciones de React Native, y está altamente optimizado para la carga eficiente de código. En versiones de producción, el código JavaScript se compila completamente a bytecode con anticipación. El bytecode se carga en memoria bajo demanda y no necesita ser analizado como sí lo requiere JavaScript plano.

información

Lee más sobre el uso de Hermes en React Native aquí.

Recomendado: Carga diferida de componentes grandes

Si es poco probable que un componente con mucho código/dependencias se use durante la representación inicial de tu aplicación, puedes usar la API lazy de React para diferir la carga de su código hasta que se represente por primera vez. Normalmente, deberías considerar aplicar carga diferida a componentes de nivel de pantalla en tu aplicación, para que añadir nuevas pantallas no aumente su tiempo de inicio.

información

Lee más sobre carga diferida de componentes con Suspense, incluidos ejemplos de código, en la documentación de React.

Consejo: Evita efectos secundarios en módulos

La carga diferida de componentes puede alterar el comportamiento de tu aplicación si tus módulos de componentes (o sus dependencias) tienen efectos secundarios, como modificar variables globales o suscribirse a eventos fuera de un componente. La mayoría de los módulos en aplicaciones React no deberían tener efectos secundarios.

SideEffects.tsx
import Logger from './utils/Logger';

// 🚩 🚩 🚩 Side effect! This must be executed before React can even begin to
// render the SplashScreen component, and can unexpectedly break code elsewhere
// in your app if you later decide to lazy-load SplashScreen.
global.logger = new Logger();

export function SplashScreen() {
// ...
}

Avanzado: Llama a require en línea

A veces puedes querer diferir la carga de cierto código hasta que lo uses por primera vez, sin emplear lazy ni import() asíncrono. Puedes lograrlo usando la función require() donde normalmente usarías un import estático al inicio del archivo.

VeryExpensive.tsx
import {Component} from 'react';
import {Text} from 'react-native';
// ... import some very expensive modules

export default function VeryExpensive() {
// ... lots and lots of rendering logic
return <Text>Very Expensive Component</Text>;
}
Optimized.tsx
import {useCallback, useState} from 'react';
import {TouchableOpacity, View, Text} from 'react-native';
// Usually we would write a static import:
// import VeryExpensive from './VeryExpensive';

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>
);
}

Avanzado: Inserción automática de llamadas require

Si usas la CLI de React Native para construir tu aplicación, las llamadas require (pero no los import) se insertarán automáticamente, tanto en tu código como en paquetes de terceros (node_modules).

tsx
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>
);
}
información

Algunos frameworks de React Native desactivan este comportamiento. En particular, en proyectos Expo, las llamadas require no se insertan por defecto. Puedes activar esta optimización editando la configuración Metro de tu proyecto y estableciendo inlineRequires: true en getTransformOptions.

Inconvenientes de la inserción de require

Insertar llamadas require altera el orden de evaluación de los módulos, e incluso puede hacer que algunos módulos nunca se evalúen. Esto generalmente es seguro automáticamente, porque los módulos JavaScript suelen escribirse sin efectos secundarios.

Si uno de tus módulos tiene efectos secundarios (por ejemplo, inicializa un mecanismo de registro o modifica una API global usada por tu código), podrías observar comportamientos inesperados o incluso fallos. En esos casos, quizá quieras excluir ciertos módulos de esta optimización o desactivarla completamente.

Para desactivar toda inserción automática de llamadas require:

Actualiza tu metro.config.js para establecer la opción del transformador inlineRequires en false:

metro.config.js
module.exports = {
transformer: {
async getTransformOptions() {
return {
transform: {
inlineRequires: false,
},
};
},
},
};

Para solo excluir ciertos módulos de la inserción de require:

Hay dos opciones relevantes del transformador: inlineRequires.blockList y nonInlinedRequires. Consulta el fragmento de código para ver ejemplos de cómo usar cada una.

metro.config.js
module.exports = {
transformer: {
async getTransformOptions() {
return {
transform: {
inlineRequires: {
blockList: {
// require() calls in `DoNotInlineHere.js` will not be inlined.
[require.resolve('./src/DoNotInlineHere.js')]: true,

// require() calls anywhere else will be inlined, unless they
// match any entry nonInlinedRequires (see below).
},
},
nonInlinedRequires: [
// require('react') calls will not be inlined anywhere
'react',
],
},
};
},
},
};

Consulta la documentación de getTransformOptions en Metro para más detalles sobre cómo configurar y ajustar tus llamadas require en línea.

Avanzado: Usa paquetes de módulos de acceso aleatorio (no-Hermes)

consejo

No compatible con Hermes. El bytecode de Hermes no es compatible con el formato RAM bundle, y ofrece el mismo (o mejor) rendimiento en todos los casos.

Los paquetes de módulos de acceso aleatorio (RAM bundles) funcionan combinados con las técnicas mencionadas para limitar la cantidad de código JavaScript que necesita ser analizado y cargado en memoria. Cada módulo se almacena como una cadena (o archivo) separada que solo se analiza cuando el módulo necesita ejecutarse.

Los RAM bundles pueden estar físicamente divididos en archivos separados, o usar el formato indexado, que consiste en una tabla de búsqueda de múltiples módulos en un único archivo.

On Android enable the RAM format by editing your android/app/build.gradle file. Before the line apply from: "../../node_modules/react-native/react.gradle" add or amend the project.ext.react block:

project.ext.react = [
bundleCommand: "ram-bundle",
]

Use the following lines on Android if you want to use a single indexed file:

project.ext.react = [
bundleCommand: "ram-bundle",
extraPackagerArgs: ["--indexed-ram-bundle"]
]

Consulta la documentación de getTransformOptions en Metro para más detalles sobre cómo configurar y ajustar tu compilación de RAM bundle.