Angular es un framework frontend de JavaScript desarrollado por Google para crear aplicaciones web escalables de nivel empresarial. Algunas de estas aplicaciones pueden llegar a ser bastante grandes, afectando al tiempo de carga de tu aplicación.

Para reducir el tiempo de carga y mejorar la experiencia general de tus usuarios, puedes utilizar una técnica conocida como carga diferida (lazy loading). Esta función nativa de Angular te permite cargar primero sólo las partes necesarias de la aplicación web y, a continuación, cargar otros módulos según sea necesario.

En este artículo, aprenderás sobre la carga diferida y cómo puede ayudarte a acelerar tu aplicación web.

¿Qué Es la Carga Diferida?

La carga diferida se refiere a la técnica de cargar los elementos de una página web sólo cuando son necesarios. Su contrapartida es la carga ansiosa (eager loading), cuando todo se carga – o intenta cargarse – inmediatamente. Obtener todas las imágenes, vídeos, CSS y código JavaScript de forma ansiosa puede implicar largos tiempos de carga, una mala noticia para los usuarios.

La carga diferida se utiliza a menudo para imágenes y vídeos en sitios que alojan mucho contenido. En lugar de cargar todos los medios a la vez, lo que consumiría mucho ancho de banda y entorpecería la visualización de la página, esos elementos se cargan cuando su ubicación en la página está a punto de aparecer.

Angular es un framework de aplicaciones de una sola página que depende de JavaScript para gran parte de su funcionalidad. La colección de JavaScript de tu aplicación puede hacerse grande fácilmente a medida que la aplicación crece, y esto conlleva el correspondiente aumento del uso de datos y del tiempo de carga. Para acelerar las cosas, puedes utilizar la carga diferida para obtener primero los módulos necesarios y aplazar la carga de otros módulos hasta que sean necesarios.

Ventajas de la Carga Diferida en Angular

La carga diferida ofrece ventajas que harán que tu sitio sea más fácil de usar. Entre ellas están:

  • Tiempo de carga más rápido: JavaScript contiene instrucciones para mostrar tu página y cargar sus datos. Por ello, es un recurso que bloquea la renderización. Esto significa que el navegador tiene que esperar a cargar todo el JavaScript antes de mostrar tu página. En la carga diferida de Angular, el JavaScript se divide en fragmentos que se cargan por separado. El trozo inicial sólo contiene la lógica necesaria para el módulo principal de la página. Se carga ansiosamente y, a continuación, se cargan diferidamente los módulos restantes. Al reducir el tamaño del trozo inicial, harás que el sitio se cargue y se renderice más rápido.
  • Menos uso de datos: Al dividir los datos en trozos y cargarlos según sea necesario, podrías utilizar menos ancho de banda.
  • Conservación de los recursos del navegador: Como el navegador sólo carga los trozos que necesita, no malgasta memoria ni CPU intentando interpretar y renderizar código que no es necesario.

Implementación de la Carga Diferida en Angular

Para seguir este tutorial, necesitarás lo siguiente:

  • NodeJS instalado
  • Conocimientos básicos de Angular

Crea tu proyecto

Utilizarás la CLI de Angular para crear tu proyecto. Puedes instalar la CLI utilizando npm ejecutando el comando:

npm install -g @angular/cli

Después de eso, crea un proyecto llamado Lazy Loading Demo como este:

ng new lazy-loading-demo --routing

Ese comando crea un nuevo proyecto Angular, completo con enrutamiento. Trabajarás exclusivamente en la carpeta src/app, que contiene el código de tu aplicación. Esta carpeta contiene tu archivo de enrutamiento principal, app-routing.module.ts. La estructura de la carpeta debería ser la siguiente:

La estructura de carpetas de un proyecto Angular.
La estructura de carpetas de un proyecto Angular.

Crear un módulo de funciones con rutas

A continuación, crearás un módulo de funciones que se cargará diferidamente. Para crear este módulo, ejecuta este comando:

ng generate module blog --route blog --module app.module

Este comando crea un módulo llamado BlogModule, junto con el enrutamiento. Si abres src/app/app-routing.module.ts , verás que ahora tiene este aspecto:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

const routes: Routes = [ { path: 'blog', loadChildren: () => import('./blog/blog.module').then(m => m.BlogModule) }];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { } 

La parte importante para la carga diferida es la tercera línea:

const routes: Routes = [ { path: 'blog', loadChildren: () => import('./blog/blog.module').then(m => m.BlogModule) }];

Esa línea define las rutas. La ruta para el blog utiliza el argumento loadChildren en lugar de component. El argumento loadChildren indica a Angular que cargue la ruta diferidamente, es decir, que importe dinámicamente el módulo sólo cuando se visite la ruta, y luego lo devuelva al enrutador. El módulo define sus propias rutas hijas, como blog/**, en su archivo routing.module.ts. El módulo blog que has generado tiene este aspecto:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { BlogComponent } from './blog.component';

const routes: Routes = [{ path: '', component: BlogComponent }];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class BlogRoutingModule { }

Observarás que este archivo de enrutamiento contiene una única ruta, ''. Ésta resuelve para /blog y apunta al BlogComponent. Puedes añadir más componentes y definir esas rutas en este archivo.

Por ejemplo, si quisieras añadir un componente que extrajera detalles sobre una entrada concreta del blog, podrías crear el componente con este comando:

ng generate component blog/detail

Que genera el componente para los detalles del blog y lo añade al módulo blog. Para añadirle una ruta, sólo tienes que añadirlo a tu matriz de rutas:

const routes: Routes = [{ path: '', component: BlogComponent },
                        {path:"/:title",component: DetailComponent}];

Esto añade una ruta que resuelve para blog/:title (por ejemplo, blog/angular-tutorial). Esta matriz de rutas se carga de forma diferidamente y no se incluye en el paquete inicial.

Verificar la Carga Diferida

Puedes comprobar fácilmente que la carga diferida funciona ejecutando ng serve y observando la salida. En la parte inferior de la salida, deberías obtener algo como esto:

Verificación de la carga diferida mediante ng serve de Angular.
Verificación de la carga diferida mediante ng serve de Angular.

La salida anterior se divide en dos partes: Initial Chunk Files son los archivos cargados cuando la página se carga por primera vez. Lazy Chunk Files son los archivos cargados diferidamente. En este ejemplo aparece el módulo blog.

Comprobación de la carga diferida a través de los registros de red del navegador

Otra forma de confirmar la carga perezosa es utilizando la pestaña Red del panel Herramientas de desarrollo de tu navegador. (En Windows, es F12 en Chrome y Microsoft Edge, y CtrlShiftI en Firefox. En Mac, es ComandoOpciónI en Chrome, Firefox y Safari.)

Selecciona el filtro JS para ver sólo los archivos JavaScript cargados a través de la red. Tras la carga inicial de la aplicación, deberías obtener algo como esto:

Registro inicial de descargas de JavaScript visto en Herramientas de desarrollo.
Registro inicial de descargas de JavaScript visto en Herramientas de desarrollo.

Cuando navegues a /blog, te darás cuenta de que se ha cargado un nuevo chunk, src_app_blog_blog_module_ts.js. Esto significa que tu módulo se solicitó sólo cuando navegabas hacia esa ruta, y se está cargando diferidamente. El registro de red debería tener este aspecto:

Módulo cargado perezosamente que aparece en las descargas registradas por las Herramientas para desarrolladores.
Módulo cargado perezosamente que aparece en las descargas registradas por las Herramientas para desarrolladores.

Carga Diferida vs Carga Ansiosa

Para comparar, vamos a crear también un módulo de carga ansiosa y ver cómo afecta al tamaño del archivo y al tiempo de carga. Para demostrarlo, crearás un módulo para la autenticación. Un módulo de este tipo puede necesitar ser cargado ansiosamente, ya que la autenticación es algo que puedes exigir a todos los usuarios.

Genera un AuthModule ejecutando este comando en la CLI:

ng generate module auth --routing --module app.module

Que genera el módulo y un archivo de enrutamiento. También añade el módulo al archivo app.module.ts. Sin embargo, a diferencia del comando que utilizamos la última vez para generar un módulo, éste no añade una ruta cargada diferidamente. Utiliza el parámetro --routing en lugar de --route <name>. Eso añade el módulo de autenticación a la matriz imports en app.module.ts:

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    AuthModule //added auth module
  ],
  providers: [],
  bootstrap: [AppComponent]
})

Añadir AuthModule a tu matriz de importaciones AppModule significa que el módulo de autenticación se añade a los archivos chunk iniciales y se incluirá con el paquete JavaScript principal. Para comprobarlo, puedes volver a ejecutar ng serve y observar la salida:

Salida del comando ng serve de Angular después de añadir el módulo de autenticación.
Salida del comando ng serve de Angular después de añadir el módulo de autenticación.

Como puedes ver, el módulo de autenticación no se incluye como parte de los archivos lazy chunk. Además, el tamaño del paquete inicial ha aumentado. El archivo main.js casi ha duplicado su tamaño, pasando de 8 KB a 15 KB. En este ejemplo, el aumento es pequeño, ya que los componentes no contienen mucho código. Pero, a medida que llenes los componentes de lógica, el tamaño de este archivo aumentará, lo que constituye un argumento de peso a favor de la carga lenta.

Resumen

Has aprendido a utilizar la carga diferida en Angular para obtener módulos sólo cuando son necesarios. La carga diferida es una gran técnica para mejorar los tiempos de carga, reducir el uso de datos y utilizar mejor los recursos de tu frontend y backend.

La carga diferida, junto con tecnologías como las redes de distribución de contenidos y la minificación de JavaScript, mejorará tanto el rendimiento de tu sitio web como la satisfacción de tus usuarios.

Si estás desarrollando un sitio de WordPress y quieres aumentar realmente la velocidad, lee sobre Kinsta Edge Caching para ver algunas cifras impresionantes.

Michael Nyamande

A digital product manager by day, Michael is a tech enthusiast who is always tinkering with different technologies. His interests include web and mobile frameworks, NoCode development, and blockchain development.