Modelo de Concurrencia
Owl fue diseñado desde el principio con componentes asincrónicos. Esto proviene de los ganchos de ciclo de vida willStart
y willUpdateProps
. Con estos ganchos asincrónicos, es posible crear aplicaciones complejas y altamente concurrentes.
El modo concurrente de Owl tiene varias ventajas: permite retrasar la renderización hasta que se complete alguna operación asincrónica, permite cargar bibliotecas de forma diferida, manteniendo la pantalla anterior completamente funcional. También es bueno por razones de rendimiento: Owl lo usa para aplicar el resultado de muchas renderizaciones diferentes solo una vez en un cuadro de animación. Owl puede cancelar una renderización que ya no es relevante, reiniciarla, reutilizarla en algunos casos.
Pero aunque el uso de la concurrencia es bastante simple (y es el comportamiento predeterminado), la asincronía es difícil, porque introduce una dimensión adicional que aumenta enormemente la complejidad de una aplicación. En esta sección se explicará cómo Owl gestiona esta complejidad y cómo funciona la representación concurrente de forma general.
Rendering Components
La palabra renderizado es un poco vaga, así que vamos a explicar con más precisión el proceso mediante el cual los componentes de Owl se muestran en una pantalla.
Cuando se monta o actualiza un componente, se inicia una nueva renderización. Tiene dos fases: renderización virtual y parcheo.
Renderización virtual
Esta fase representa el proceso de renderizar una plantilla en memoria que crea una representación virtual del componente deseado (html). El resultado de esta fase es un DOM virtual.
Es asincrónico: cada subcomponente debe crearse (por lo tanto, se deberá llamar a willStart
) o actualizarse (lo que se hace con el método willUpdateProps
). Este es un proceso completamente recursivo: un componente es la raíz de un árbol de componentes y cada subcomponente debe representarse (virtualmente).
Parcheo
Una vez que se completa una representación, se aplicará en el siguiente cuadro de animación. Esto se hace de manera sincrónica: todo el árbol de componentes se conecta al DOM real.
Semántica
Aquí se ofrece una descripción informal de la forma en que se crean o actualizan los componentes en una aplicación. Aquí, las listas ordenadas describen acciones que se ejecutan de forma secuencial, mientras que las listas con viñetas describen acciones que se ejecutan en paralelo.
Scenario 1: renderizado inicial Imaginemos que queremos renderizar el siguiente árbol de componentes:
A / \ B C / \ D E
Esto es lo que sucede cada vez que montamos el componente raíz (con algún código como app.mount(document.body)
).
-
willStart
se llama enA
-
Cuando termine, se renderizará la plantilla «A».
- Se crea el componente
B
willStart
se llama enB
- Se renderiza la plantilla
B
- Se crea el componente
C
willStart
se llama enC
- Se renderiza la plantilla
C
- Se crea el componente
D
willStart
se llama enD
- Se renderiza la plantilla
D
- Se crea el componente
E
willStart
se llama enE
- Se renderiza la plantilla
E
- Se crea el componente
- Se crea el componente
-
Cada componente se integra en un elemento DOM independiente, en el siguiente orden:
E
,D
,C
,B
,A
. (De esta forma, el árbol DOM completo se crea en una sola pasada) -
El elemento raíz del componente
A
en realidad se agrega adocument.body
-
El método
mounted
se llama recursivamente en todos los componentes en el siguiente orden:E
,D
,C
,B
,A
.
Scenario 2: Actualizar un componente. Ahora, supongamos que el usuario hizo clic en algún botón en “C”, y esto genera una actualización de estado, que se supone que debe:
- actualiza
D
, - elimina
E
, - agrega un nuevo componente
F
.
Entonces, el árbol de componentes debería verse así:
A / \ B C / \ D F
Esto es lo que hará Owl:
-
Debido a un cambio de estado, se llama al método
render
enC
-
La plantilla
C
se vuelve a representar- El componente
D
se actualiza:- El gancho
willUpdateProps
se llama enD
(asincrónico) - La plantilla
D
se vuelve a renderizar
- El gancho
- Se crea el componente
F
:- El gancho
willStart
se llama enF
(asincrónico) - Se representa la plantilla
F
- El gancho
- El componente
-
Los ganchos
willPatch
se llaman recursivamente en los componentesC
,D
(no enF
, porque aún no está montado) -
Los componentes
F
,D
se parchean en ese orden -
El componente
C
está parcheado, lo que provocará recursivamente:- Gancho
willUnmount
enE
- destrucción de
E
,
- Gancho
-
El gancho
mounted
se llama enF
, los ganchospatched
se llaman enD
,C
Las etiquetas son pequeñas ayudas que facilitan la escritura de plantillas en línea. Actualmente solo hay una etiqueta disponible: xml
.
Renderizado asincrónico
Trabajar con código asincrónico siempre añade mucha complejidad a un sistema. Siempre que distintas partes de un sistema están activas al mismo tiempo, es necesario pensar detenidamente en todas las interacciones posibles. Evidentemente, esto también es cierto para los componentes Owl.
Existen dos problemas comunes diferentes con el modelo de representación asincrónica de Owl:
- Cualquier componente puede retrasar la representación (inicial y posterior) de toda la aplicación.
- Para un componente determinado, existen dos situaciones independientes que activarán una nueva representación asincrónica: un cambio en el estado o un cambio en las propiedades. Estos cambios pueden realizarse en momentos diferentes y Owl no tiene forma de saber cómo conciliar las representaciones resultantes.
A continuación se ofrecen algunos consejos sobre cómo trabajar con componentes asincrónicos:
- ¡Minimiza el uso de componentes asincrónicos!
- La carga diferida de bibliotecas externas es un buen caso de uso para la renderización asincrónica. Esto es aceptable en la mayoría de los casos, porque podemos suponer que solo tomará una fracción de segundo y solo una vez.