Skip to content

13. Ejemplo [nuxt-10]: asyncData y «cargando»

La función [asyncData] en una página permite cargar de manera asíncrona datos que, a menudo, son externos. [nuxt] espera a que finalice la función [asyncData] antes de iniciar el ciclo de vida de la página. Por lo tanto, esta solo se muestra una vez que se obtienen los datos externos. Se ejecuta tanto en el servidor como en el cliente con las siguientes reglas:

  • cuando la página se solicita directamente al servidor, solo el servidor ejecuta la función [asyncData];
  • luego, durante la navegación del cliente, solo el cliente ejecuta la función [asyncData];

Al final, solo uno de los dos, ya sea el cliente o el servidor, ejecuta la función. Además, cuando es el cliente quien ejecuta la función [asyncData], [nuxt] muestra una barra de progreso que se puede configurar.

La función [asyncData] permite entregar a los motores de búsqueda páginas con sus datos, lo que las hace más relevantes.

El ejemplo [nuxt-10] se obtiene inicialmente al copiar el proyecto [nuxt-01]:

Image

Solo cambia la página [page1].

13.1. La página [page1]

El código de la página [page1] es el siguiente:


<!-- vista n.º 1 -->
<template>
  <Layout :left="true" :right="true">
    <!-- navegación -->
    <Navigation slot="left" />
    <!-- mensaje-->
    <b-alert slot="right" show variant="primary"> Page 1 -- result={{ result }} </b-alert>
  </Layout>
</template>

<script>
/* eslint-disable no-console */
/* eslint-disable nuxt/no-timing-in-fetch-data */

import Navigation from '@/components/navigation'
import Layout from '@/components/layout'

export default {
  name: 'Page1',
  // componentes utilizados
  components: {
    Layout,
    Navigation
  },
  // datos asíncronos
  asyncData(context) {
    // registro
    console.log('[page1 asyncData started]')
    // se devuelve una promesa
    return new Promise(function(resolve, reject) {
      // se simula una función asíncrona
      setTimeout(function () {
        // se devuelve el resultado asíncrono: un número aleatorio en este caso
        resolve({ result: Math.floor(Math.random() * Math.floor(100)) })
        // log
        console.log('[page1 asyncData finished]')
      }, 5000)
    })
  },

  // ciclo de vida
  beforeCreate() {
    console.log('[page1 beforeCreate]')
  },
  created() {
    console.log('[page1 created]')
  },
  beforeMount() {
    console.log('[page1 beforeMount]')
  },
  mounted() {
    console.log('[page1 mounted]')
  }
}
</script>
  • líneas 26-39: la función [asyncData]. Ya hemos estudiado esta función (véase el párrafo del enlace). Se ejecuta antes del ciclo de vida de la página. Por esta razón, no se puede utilizar la palabra clave [this] en la función;
  • línea 30: debe devolver una promesa [Promise] o utilizar la sintaxis async / await;
  • líneas 32-37: se simula la función asíncrona de la promesa con una espera de 5 segundos (línea 37);
  • línea 34: el resultado de la función asíncrona se devuelve en forma de un objeto {result:...}. El objeto asíncrono devuelto por la función [asyncData] se integra en el objeto [data] de la página. ¿Por qué el objeto [result] está disponible en la línea 7 de la plantilla, a pesar de que la página no había definido el objeto [data]?;

13.2. Configuración de la barra de progreso de [asyncData]

Cuando la página [page1] es el destino de una navegación dentro del cliente (modo SPA), el cliente ejecuta la función [asyncData] y [nuxt] muestra entonces una barra de progreso que oculta cuando la función [asyncData] ha devuelto su resultado. La propiedad [loading] del archivo [nuxt.config.js] permite configurar esta barra:


loading: {
    color: 'blue',
    height: '5px',
    throttle: 200,
    continuous: true
},

Por defecto, la imagen de espera de [nuxt] es una barra de progreso que ocupa todo el ancho de la página. Esta barra tiene un color y un grosor. La línea de color crece progresivamente del 0 % al 100 % de su tamaño, es decir, más o menos rápido según la duración de la espera.

  • línea 2: establece el color de la barra de progreso;
  • línea 3: establece el grosor de la barra en píxeles;
  • línea 4: [throttle] es el retraso en milisegundos antes de que comience la animación. Esto evita que aparezca una imagen de animación cuando la función [asyncData] devuelve su resultado rápidamente;
  • línea 5: [continuous] establece el comportamiento de la animación de la barra de progreso. Por defecto, la barra crece progresivamente del 0 % al 100 % de su tamaño, más o menos rápido según la duración de la espera. Con [continuous:true], la barra de color crece a una velocidad constante del 0 al 100 % de su tamaño, y luego vuelve a empezar mientras la función [asyncData] no haya devuelto su resultado;

13.3. Exécution

Iniciemos la aplicación y luego solicitemos, manualmente, al servidor la página [page1]:

Image

Los registros son los siguientes:

Image

  • Se observa que solo el servidor [1] ejecutó la función [asyncData] y lo hizo antes del ciclo de la página;

Ahora analicemos la página enviada por el servidor (código fuente):


<!doctype html>
<html data-n-head-ssr>
<head>
  <title>Introduction à [nuxt.js]</title>
  <meta data-n-head="ssr" charset="utf-8">
  <meta data-n-head="ssr" name="viewport" content="width=device-width, initial-scale=1">
  <meta data-n-head="ssr" data-hid="description" name="description" content="ssr routing loading asyncdata middleware plugins store">
  <link data-n-head="ssr" rel="icon" type="image/x-icon" href="/favicon.ico">
  <base href="/nuxt-10/">
  <link rel="preload" href="/nuxt-10/_nuxt/runtime.js" as="script">
  <link rel="preload" href="/nuxt-10/_nuxt/commons.app.js" as="script">
  <link rel="preload" href="/nuxt-10/_nuxt/vendors.app.js" as="script">
  <link rel="preload" href="/nuxt-10/_nuxt/app.js" as="script">
...
</head>
<body>
  <div data-server-rendered="true" id="__nuxt">
    <div id="__layout">
      <div class="container">
        <div class="card">
          <div class="card-body">
            <div role="alert" aria-live="polite" aria-atomic="true" align="center" class="alert alert-success">
            <h4>[nuxt-10] : asyncData et loading</h4>
              </div>
            <div>
              <div class="row">
                <div class="col-2">
                  <ul class="nav flex-column">
                    <li class="nav-item">
                      <a href="/nuxt-10/" target="_self" class="nav-link">
                        Home
                      </a>
                    </li>
                    <li class="nav-item">
                      <a href="/nuxt-10/page1" target="_self" class="nav-link active nuxt-link-active">
                        Page 1
                      </a>
                    </li>
                    <li class="nav-item">
                      <a href="/nuxt-10/page2" target="_self" class="nav-link">
                        Page 2
                      </a>
                    </li>
                  </ul>
                </div> <div class="col-10"><div role="alert" aria-live="polite" aria-atomic="true" class="alert alert-primary"> Page 1 -- result=3 </div></div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <script>window.__NUXT__ = (function (a, b, c) {
  return {
    layout: "default", data: [{ result: 3 }], error: null, serverRendered: true,
    logs: [
      { date: new Date(1574939615256), args: ["[page1 asyncData started]"], type: a, level: b, tag: c },
      { date: new Date(1574939620263), args: ["[page1 asyncData finished]"], type: a, level: b, tag: c },
      { date: new Date(1574939620285), args: ["[page1 beforeCreate]"], type: a, level: b, tag: c },
      { date: new Date(1574939620287), args: ["[page1 created]"], type: a, level: b, tag: c }
    ]
  }
    }("log", 2, ""));</script>
  <script src="/nuxt-10/_nuxt/runtime.js" defer></script>
  <script src="/nuxt-10/_nuxt/commons.app.js" defer></script>
  <script src="/nuxt-10/_nuxt/vendors.app.js" defer></script>
  <script src="/nuxt-10/_nuxt/app.js" defer></script>
</body>
</html>
  • línea 55: se observa que el servidor envió al cliente una matriz [data] que contiene el objeto [result:3], el cual fue integrado al objeto [data] de la página [page1] del servidor. Para que el cliente pueda hacer lo mismo y, por lo tanto, mostrar la misma página que el servidor, este le transmite el objeto [result]. Recordemos que el cliente no ejecutará la función [asyncData]. Simplemente utilizará los datos calculados por el servidor;

Ahora naveguemos de la página [Home] a la página [Page 1] utilizando el menú de navegación:

Image

  • En [1], aparece la barra de progreso;

Al cabo de 5 segundos, aparece la página [Page 1]:

Image

Los registros son los siguientes:

Image

Se observa que el cliente ejecutó la función [asyncData] antes del ciclo de vida de la página.