Skip to content

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

La función [asyncData] de una página permite cargar de forma asíncrona datos que suelen ser 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 obtenidos los datos externos. Se ejecuta tanto en el servidor como en el cliente siguiendo estas reglas:

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

En definitiva, solo uno de los dos, el cliente o el servidor, ejecuta la función. Por otra parte, 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 proporcionar 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 copiando 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 de forma asíncrona: 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 apartado del enlace). Se ejecuta antes del ciclo de vida de la página. Por este motivo, 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 eso el objeto [result] está disponible en la línea 7 de la plantilla, aunque la página no hubiera 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, a continuación, [nuxt] muestra 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, más o menos rápido en función de 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 tiempo de espera en milisegundos antes de que comience la animación. Esto evita que aparezca la 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, a continuación, vuelve a empezar mientras la función [asyncData] no haya devuelto su resultado;

13.3. Exécution

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

Image

Los registros son los siguientes:

Image

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

Ahora examinemos 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: vemos que el servidor ha enviado al cliente una matriz [data] que contiene el objeto [result:3], el cual se ha integrado en el 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 va a ejecutar la función [asyncData]. Simplemente utilizará los datos calculados por el servidor;

Ahora naveguemos desde 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 ha ejecutado la función [asyncData] antes del ciclo de vida de la página.