The playground

More information here

UX más suave al cargar la página con Resolutores Angulares

Como desarrollador, siempre está buscando optimizar su código. Esto incluye la velocidad a la que presenta al usuario la interfaz de usuario completamente cargada, que a menudo depende de los datos que provienen de una base de datos. Inevitablemente, comienza a buscar formas de resolver los datos inmediatamente después de navegar a una nueva página/área […]

Como desarrollador, siempre está buscando optimizar su código. Esto incluye la velocidad a la que presenta al usuario la interfaz de usuario completamente cargada, que a menudo depende de los datos que provienen de una base de datos.

Inevitablemente, comienza a buscar formas de resolver los datos inmediatamente después de navegar a una nueva página/área de su aplicación, sin que el usuario encuentre lo que se conoce como page JANK.

Esto es cuando la página se mueve hacia arriba y hacia abajo mientras se cargan ciertos componentes. Puede afectar significativamente la experiencia de usuario, hasta el punto de que se ve ‘buggy’.

Angular proporciona un enfoque intuitivo para la obtención previa de datos antes de que se cargue la ruta; antes de que se resuelva la ruta navegada.

Se denomina Solucionador angular.

Un Solucionador Angular es esencialmente un Servicio Angular. Una clase inyectable que se proporciona a un módulo de enrutamiento en la configuración de ruta. Este tipo especial de servicio se inyecta y se ejecuta cuando se navega por la ruta contenedora.

El Solucionador resuelve los datos antes de la carga de la página, que está disponible a través del servicio ActivatedRoute. Esto proporciona una manera simple y eficiente de garantizar que su usuario tenga los datos lo más rápido posible antes de que un componente importante para la carga inicial de la página los necesite.

Otra forma de usar un solucionador angular es usarlo como método para rellenar los metadatos SEO al instante.

Con un solucionador, proporciona una garantía de que los datos existirán antes de que se cargue la página, asegurándose de que todo tenga lo que necesita en la inicialización.

Desglosemos el solucionador angular

Un solucionador angular es una clase que implementa la interfaz Resolve. La interfaz Resolve requiere que implemente una función dentro de la clase llamada resolve.

Aquí está la firma de la interfaz de resolución

export interface Resolve<T> {
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<T> | Promise<T> | T {
return 'data';
}
}

Como podemos ver en la firma de la interfaz, requiere un argumento genéricoT que será el tipo de nuestros datos resueltos.

La determinación de la función devuelve un ObservablePromise o sólo los datos de tipo T . Por lo tanto, se sugiere que esto se maneje de forma asincrónica, especialmente si se recuperan los datos de la base de datos.

El propósito principal de la función resolve es que debe completarse. Este hecho debe recordarse al recuperar datos en observables. El observable debe completarse. Después de todo, es un solucionador.

Si el observable no se completa, los datos nunca se resolverán y la página nunca se cargará. Por lo tanto, debe definir el punto en el que no necesita tomar más valores y los datos pueden resolverse, ya que tiene todo lo que necesita de la base de datos. Cuando se utilizan flujos de datos asíncronos, como observables, este es un caso de uso para operadores canalizables de RXJS.

Los operadores pipeables que vienen a la mente cuando se piensa en completar un flujo de datos basado en una condición, es una combinación de filtertakefirst . Con esta combinación, se puede filtrar todos los valores que usted no desea llevar a cabo, tales como null o undefined o una matriz vacía , luego take el primer valor válido con la etiqueta take(1).Los operadores

que pueden ser necesarios para completar un observable temprano cuando se encuentran problemas o errores, en los que querrá devolver null o redirigir, son catchErrory timeout. Una combinación de timeout y catchError es útil si sus datos están tardando demasiado y desea devolver null para que pueda intentarlo de nuevo dentro del componente, o desea redirigir.

Si sus datos no se resuelven rápidamente, se basan en filtros complejos, lógica, grandes cantidades de llamadas a bases de datos, es probable que experimente problemas de vez en cuando.

Lo mejor es determinar la menor cantidad de llamadas a la base de datos y los datos mínimos que se necesitan para cargar la página con éxito y gracia.

Por lo tanto, puede beneficiarse de dedicar algún tiempo, antes de implementar su resolución, para centrarse en separar el contenido «arriba del pliegue» de los datos que se pueden cargar cuando se inicializa la página.

Por lo tanto, puede dividir los datos necesarios para una experiencia de usuario fluida, del resto de los datos que se podrían llamar desde el componente, en lugar del solucionador.

A continuación, puede tratar exclusivamente con el contenido mínimo, por encima del pliegue, a través del solucionador.

Este enfoque dinámico para la carga de páginas se puede ayudar con el uso de esqueletos. De modo que si el usuario se desplaza hacia abajo al instante, puede darle al usuario la indicación de que el contenido se está cargando, mejorando posteriormente la experiencia de usuario.

Paso 1: Creación del Solucionador

Necesitamos crear el Solucionador Angular. Sin embargo, no hay un comando de CLI Angular que genere un solucionador. Por lo tanto, tendremos que escribir el decorador (metadatos de resolución) nosotros mismos.

Afortunadamente, son solo unas pocas líneas de código las que forman la repetición de un solucionador, y podemos tomar el decorador inyectable de un servicio existente si tiene dificultades para recordarlo.

Anote la clase de resolución de perfiles con un decorador inyectable

Primero, proporcionamos el decorador inyectable con providedIn: any en la configuración.

@Injectable({ providedIn: 'any'})

A continuación, nombraremos nuestro solucionador añadiendo la convención Resolver. Para este ejemplo, resolveremos datos de perfil (datos de usuario), por lo que lo llamaremos ProfileResolver .

Como es un solucionador, y Angular reconoce la función de los solucionadores, podemos implementar la clase Resolve, que proporcionará la firma que tenemos que implementar en nuestra función resolve para resolver con éxito los datos.

@Injectable({providedIn: 'any'})
export class ProfileResolver implements Resolve<Profile> {
}

Nuestra función resolve devolverá un Observable con datos conformes a la interfaz Profile. Por lo tanto, proporcionaremos la interfaz Profile como argumento genérico para la clase de resolución y la función resolve(). De esta manera nos hemos ajustado a los requisitos angulares para un resolutor.

resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<T> | Promise<T> | T {
return;
}

El resolver la aplicación nos da dos parámetros, si son necesarias, route y state . Estos se rellenan automáticamente y son accesibles desde nuestra función resolve().

A continuación, necesitamos resolver datos reales de la base de datos, que será nuestro siguiente paso.

Recuperar los datos de la base de datos

Para recuperar los datos de nuestra función resolve, necesitaremos inyectar el servicio que proporciona los datos; uno que interactúa con la base de datos.

Tomamos lo que necesitamos de él para resolverlo rápidamente para que el usuario navegue con rapidez y éxito. A los efectos de esta demostración, no nos preocuparemos por el servicio subyacente que se ocupa de la base de datos. Simplemente inyectaremos el servicio usando inyección de dependencias en el argumento constructor para nuestra clase ProfileResolver.

Como nuestros datos vienen en forma de un flujo de datos observable con múltiples valores que emiten de forma asíncrona, solo necesitaremos take(1) utilizando el operador pipeable take importado de rxjs/operator . De lo contrario, lo observable nunca se completaría, y el solucionador nunca resolve resolvería.

Solo necesitamos un valor de emisión y take completa el observable para nosotros.

Es tan simple como eso crear un solucionador; solo necesitamos devolver el observable en la función resolve() de la que angular manejará la suscripción.

La clase ProfileResolver

Manejamos cualquier error al recuperar los datos redirigiendo a una ruta principal.Bono

: Rellene metadatos SEO dinámicos rápidamente antes de que la ruta se haya cargado

Los beneficios de rellenar nuestras etiquetas <meta> tienen beneficios obvios al instante. Cuanto más rápido se rellenan nuestros metadatos de SEO, más rápido refleja correctamente y con precisión el contenido de la página.

Esto significa que es más fácil y rápido para los robots, como los operados por motores de búsqueda como Google y Bing, rastrear su sitio y recuperar el contenido.

Esto no es tan importante en páginas pre-renderizadas o aquellas que son renderizadas por Angular Universal, porque todo el renderizado se completa antes de que los robots reciban el contenido.

Sin embargo, si confías en la capacidad (a menudo cuestionable) de los robots de Google para analizar javascript para tu SEO, o tienes una solución bajo demanda como puppeteer que necesita la garantía de que el SEO será correcto antes de devolver el DOM renderizado, entonces un solucionador que incluya SEO debería ayudarte. Por lo tanto, ayuda cuando el rastreador tiene un tiempo limitado.

También separa las preocupaciones del componente, para que el componente no tenga que lidiar con nada relacionado con el SEO. Una de las principales razones por las que me gustan los resolutores.

Paso 2: Inyecte el solucionador en el módulo de enrutamiento

El módulo de trazado de perfiles donde proporcionaremos nuestro solucionador es un módulo cargado perezosamente. Por lo tanto , nuestra ruta raíz estará vacía con el parámetro token userSlug, que necesitaremos para recuperar los datos de perfil correctos.

Para proporcionar nuestro solucionador, solo proporcionamos un objeto con el nombre de nuestros datos como clave y el solucionador específico como el valor que será responsable de resolver esos datos.

Puedes nombrar la clave como quieras, pero solo la llamaremos datos.

Nuestro módulo Profilerouting

Eso es todo lo que se requiere en el módulo de enrutamiento para que podamos usar nuestro solucionador.

A continuación, necesitamos recuperar y usar nuestros datos en el componente.

Paso 3: Inicializar el componente con datos resueltos

Ahora que hemos resuelto nuestros datos sobre la activación de la ruta, se puede acceder a los datos a través del Servicio ActivatedRoute. Como estamos tratando con observables, a lo largo de la aplicación, crearemos un flujo que se vinculará a la propiedad data que serán nuestros datos resueltos.

Primero, inyectaremos el ActivatedRoute en el constructor de nuestro ProfileComponent. A continuación, asignaremos this.route.data al profile$ observable. También queremos cambiar a usar un observable cuando lleguen datos actualizados de la base de datos para que tengamos datos nuevos cuando interactuemos con la aplicación.

Para esto, usaremos startWith para comenzar nuestra transmisión con el valor al que se puede acceder fácilmente desde this.route.snapshot.data. Luego accedemos a la propiedad data como this.route.snapshot.datastartWith indica un valor con el que comenzar, como la primera emisión de nuestra corriente.

Nuestro componente de perfil

Lo que hacen los datos de acceso inmediato para el componente

Los datos de acceso inmediato reducen el tiempo dedicado a cargar las partes individuales de esa página, que es observado por el usuario. El resultado de no usar un solucionador como este es que la página puede parecer que se carga de forma fragmentada, lo que no es agradable a la vista.

En consecuencia, deberá prestar atención a qué elementos de sus plantillas HTML dependen de qué datos. A continuación, debe escribir su resolución para admitir estos elementos y el efecto general en la experiencia de usuario de carga de página.

Hay varias formas en que el componente puede cargar fragmentado

  • Una de ellas es si tiene un ngIf en varias partes de su plantilla HTML.
  • Otro es ngFor.

es la mejor práctica para limitar la cantidad de ngIf ‘s de escribir para los propósitos de la limitación de la cantidad de redimensionar el navegador tiene que hacer.

Cargar la página antes de obtener los datos puede hacer que partes de la página salten, se retrasen y redimensionen constantemente, lo que hace que la experiencia de usuario se vea afectada.

Implementar un solucionador podría ser la diferencia entre el usuario que experimenta 3-5 segundos de salto y cambio de tamaño frente a 0.5 segundos, que a menudo es demasiado rápido para dañar la experiencia de usuario en general.

¡Eso es todo! Tenemos un solucionador con una experiencia de usuario mejorada al cargar la página.

Deja una respuesta

Tu dirección de correo electrónico no será publicada.