Skip to content

14. Ejemplo [nuxt-11]: personalización de la imagen de espera

Por defecto, la imagen de espera de [nuxt] es una barra de progreso. El ejemplo [nuxt-11] muestra que se puede sustituir por una imagen de espera propia:

Image

El ejemplo [nuxt-11] también muestra cómo gestionar los errores de carga.

Image

El ejemplo [nuxt-11] se obtiene inicialmente copiando el ejemplo [nuxt-10]:

Image

Vamos a añadir en [1] un complemento para el cliente cuya función será gestionar eventos entre componentes.

14.1. El complemento [event-bus]

El complemento [event-bus] se ejecutará tanto en el cliente como en el servidor, pero veremos que no funciona en el lado del servidor. Su código es el siguiente:


// se crea un bus de eventos entre las vistas
import Vue from 'vue'
export default (context, inject) => {
  // el bus de eventos
  const eventBus = new Vue()
  // inyección de una función [eventBus] en el contexto
  inject('eventBus', () => eventBus)
}
  • línea 5: el bus de eventos es una instancia de la clase [Vue]. De hecho, esta clase dispone de métodos para gestionar eventos:
    • [$emit]: para emitir un evento;
    • [$on]: para escuchar un evento concreto;

Este bus de eventos solo gestionará un evento, [loading], que será utilizado por las páginas para iniciar o detener la animación de espera hasta que finalice una función asíncrona;

  • línea 7: se crea una función [$eventBus] (primer argumento) cuya función será devolver el objeto [eventBus] que acabamos de crear (segundo argumento). Esta función se inyecta en el contexto para que esté disponible en los objetos [context.app] y [this] de las páginas;

14.2. El diseño [default.vue]

El diseño [default.vue] evoluciona de la siguiente manera:


<template>
  <div class="container">
    <b-card>
      <!-- un mensaje -->
      <b-alert show variant="success" align="center">
        <h4>[nuxt-11] : personnalisation de l'attente, gestion des erreurs</h4>
      </b-alert>
      <!-- vista actual del enrutamiento -->
      <nuxt />
      <!-- cargando -->
      <b-alert v-if="showLoading" show variant="light">
        <strong>Requête au serveur de données en cours...</strong>
        <div class="spinner-border ml-auto" role="status" aria-hidden="true"></div>
      </b-alert>
      <!-- error de carga -->
      <b-alert v-if="showErrorLoading" show variant="danger">
        <strong>La requête au serveur de données a échoué : {{ errorLoadingMessage }}</strong>
      </b-alert>
    </b-card>
  </div>
</template>

<script>
/* eslint-disable no-console */
export default {
  name: 'App',
  data() {
    return {
      showLoading: false,
      showErrorLoading: false
    }
  },
  // ciclo de vida
  beforeCreate() {
    console.log('[default beforeCreate]')
  },
  created() {
    console.log('[default created]')
    // se escucha el evento [loading]
    this.$eventBus().$on('loading', this.mShowLoading)
    // así como el evento [errorLoadingMessage]
    this.$eventBus().$on('errorLoading', this.mShowErrorLoading)
  },
  beforeMount() {
    console.log('[default beforeMount]')
  },
  mounted() {
    console.log('[default mounted]')
  },
  methods: {
    // gestión de la carga
    mShowLoading(value) {
      console.log('[default mShowLoading], showLoading=', value)
      this.showLoading = value
    },
    // error de carga
    mShowErrorLoading(value, errorLoadingMessage) {
      console.log('[default mShowErrorLoading], showErrorLoading=', value, 'errorLoadingMessage=', errorLoadingMessage)
      this.showErrorLoading = value
      this.errorLoadingMessage = errorLoadingMessage
    }
  }
}
</script>
  • líneas 11-14: la animación de espera. Solo se muestra si la propiedad [showLoading] es verdadera (línea 29);
  • líneas 16-18: el mensaje de error de carga. Solo se muestra si la propiedad [showErrorLoading] (línea 30) es verdadera;
  • líneas 29-30: al cargarse inicialmente el componente, se ocultan tanto la animación de espera como el mensaje de error;
  • líneas 37-43: al crearse, la página escucha el evento [loading] (primer argumento) en el bus de eventos creado por el complemento. Al recibirlo, ejecuta el método [mShowLoading] de las líneas 52-55 (segundo argumento);
  • líneas 52-55: el valor recibido por el método [mShowLoading] será un valor booleano (true/false). Sirve para mostrar u ocultar el mensaje de espera;
  • líneas 41-42: cuando se crea, la página escucha el evento [errorLoading] (primer argumento) en el bus de eventos creado por el complemento. Al recibirlo, ejecuta el método [mShowErrorLoading] de las líneas 57-61 (segundo argumento);
  • línea 57: el método [mShowErrorLoading] recibe dos argumentos:
    • el primer argumento es un valor booleano (true/false) para mostrar u ocultar el mensaje de error;
    • el segundo argumento solo está presente si se ha producido un error. Representa el mensaje de error que se va a mostrar;
  • los registros de las líneas 53 y 58 nos mostrarán que los métodos [showLoading] y [showErrorLoading] no se ejecutan en el servidor;

14.3. La página [page1]

El código de la página [page1] evoluciona de la siguiente manera:


<!-- 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]')
    // Inicio de la espera
    context.app.$eventBus().$emit('loading', true)
    // sin errores
    context.app.$eventBus().$emit('errorLoading', false)
    // se devuelve una promesa
    return new Promise(function(resolve, reject) {
      // se simula una función asíncrona
      setTimeout(function() {
        // fin de la espera
        context.app.$eventBus().$emit('loading', false)
        // registro
        console.log('[page1 asyncData finished]')
        // se devuelve el resultado asíncrono: un número aleatorio aquí
        resolve({ result: Math.floor(Math.random() * Math.floor(100)) })
      }, 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>
  • los cambios se producen en la función [asyncData], en las líneas 26-47;
  • líneas 29-30: antes de que comience la función asíncrona, se emite el evento [loading] dirigido a las demás páginas de la aplicación. Cabe recordar que en [asyncData] no se tiene acceso al objeto [this], que aún no se ha creado. Por lo tanto, se utiliza el contexto que recibe como argumento la función [asyncData] (línea 26);
  • línea 30: se utiliza el bus de eventos para indicar que la carga va a comenzar;
  • línea 38: se utiliza el bus de eventos para indicar que la carga ha finalizado;

Nota: Durante la ejecución, cuando se solicita la página [page1] al servidor, no se ve la imagen de espera. En los registros se observa que, en el lado del servidor, no se invoca el método [default.mShowLoading]. De todos modos, ver la imagen de espera no tiene sentido cuando se solicita la página al servidor. Este no envía la página al navegador del cliente hasta que la función [asyncData] haya finalizado. La imagen de espera resulta entonces innecesaria. Este será el caso para todas las páginas de la aplicación solicitadas directamente al servidor.

14.4. La página [index]

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


<!-- página principal -->
<template>
  <Layout :left="true" :right="true">
    <!-- navegación -->
    <Navigation slot="left" />
    <!-- mensaje-->
    <b-alert slot="right" show variant="warning">
      Home
    </b-alert>
  </Layout>
</template>

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

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

export default {
  name: 'Home',
  // componentes utilizados
  components: {
    Layout,
    Navigation
  },
  // datos asíncronos
  asyncData(context) {
    // registro
    console.log('[page1 asyncData started]')
    // Inicio de la espera
    context.app.$eventBus().$emit('loading', true)
    // sin errores
    context.app.$eventBus().$emit('errorLoading', false)
    // se devuelve una promesa
    return new Promise(function(resolve, reject) {
      // se simula una función asíncrona
      setTimeout(function() {
        // fin de la espera
        context.app.$eventBus().$emit('loading', false)
        // registro
        console.log('[page1 asyncData finished]')
        // se devuelve un error
        reject(new Error("le serveur n'a pas répondu assez vite"))
      }, 5000)
    }).catch((e) => context.error({ statusCode: 500, message: e.message }))
  },
  // ciclo de vida
  beforeCreate() {
    console.log('[home beforeCreate]')
  },
  created() {
    console.log('[home created]')
  },
  beforeMount() {
    console.log('[home beforeMount]')
  },
  mounted() {
    console.log('[home mounted]')
    // sin error
    this.$eventBus().$emit('errorLoading', false)
  }
}
</script>
  • líneas 30-49: la función [asyncData] es idéntica a la de la página [page1], salvo por un detalle: en la línea 46, se termina la función asíncrona en caso de fallo (utilizando el método [reject]);
  • línea 46: el parámetro de la función [reject] es una instancia de la clase [Error]. El parámetro del constructor [Error] es el mensaje de error;
  • línea 48: este error es interceptado por el método [catch] de [Promise], que recibe el error como parámetro. A continuación, se utiliza la función [context.error] para declarar el error. El parámetro de la función [context.error] es un objeto que, en este caso, tiene dos propiedades:
    • [statusCode]: un código de error HTTP;
    • [message]: un mensaje de error;

Tanto si [asyncData] se ejecuta en el cliente como en el servidor, en caso de error [context.error], [nuxt] muestra la página [layouts / error.vue]:

Image

Aunque se trata de una página, la página [error.vue] se busca en la carpeta [layouts] (¿quizás para evitar que se incluya en las rutas de la aplicación?). En este caso, la página [error.vue] es la siguiente:


<!-- definición HTML de la vista -->
<template>
  <!-- diseño de página -->
  <Layout :left="true" :right="true">
    <!-- alerta en la columna de la derecha -->
    <template slot="right">
      <!-- mensaje sobre fondo amarillo -->
      <b-alert show variant="danger" align="center">
        <h4>L'erreur suivante s'est produite : {{ JSON.stringify(error) }}</h4>
      </b-alert>
    </template>
    <!-- menú de navegación en la columna de la izquierda -->
    <Navigation slot="left" />
  </Layout>
</template>

<script>
/* eslint-disable no-undef */
/* eslint-disable no-console */
/* eslint-disable nuxt/no-env-in-hooks */

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

export default {
  name: 'Error',
  // componentes utilizados
  components: {
    Layout,
    Navigation
  },
  // propiedad [props]
  props: { error: { type: Object, default: () => 'waiting ...' } },
  // ciclo de vida
  beforeCreate() {
    // cliente y servidor
    console.log('[error beforeCreate]')
  },
  created() {
    // cliente y servidor
    console.log('[error created, error=]', this.error)
  },
  beforeMount() {
    // solo cliente
    console.log('[error beforeMount]')
  },
  mounted() {
    // solo cliente
    console.log('[error mounted]')
  }
}
</script>

Cuando [nuxt] muestra la página [error.vue], le pasa como propiedad [props] el error que se ha producido (línea 33). Si el error lo ha provocado [context.error(objet1)], la propiedad [props] de la página [error.vue] tendrá el valor [objet1]. La documentación de [nuxt] indica que [objet1] debe tener, como mínimo, los atributos de [statusCode, message]. La línea 9 muestra la cadena jSON del objeto [objet1] recibido.

14.5. La página [page2]

La página [page2] muestra otra forma de gestionar el error:

  • en [page1], el error se muestra en una página aparte, [error.vue];
  • en [page2], el error se mostrará en la página [page2] que lo ha provocado;

El código de [page2] es el siguiente:


<!-- vista n.º 2 -->
<template>
  <Layout :left="true" :right="true">
    <!-- navegación -->
    <Navigation slot="left" />
    <!-- mensaje -->
    <b-alert slot="right" show variant="secondary">
      Page 2
    </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: 'Page2',
  // componentes utilizados
  components: {
    Layout,
    Navigation
  },
  // datos asíncronos
  asyncData(context) {
    // registro
    console.log('[page2 asyncData started]')
    // Inicio de la espera
    context.app.$eventBus().$emit('loading', true)
    // sin errores
    context.app.$eventBus().$emit('errorLoading', false)
    // se devuelve una promesa
    return new Promise(function(resolve, reject) {
      // se simula una función asíncrona
      setTimeout(function() {
        // fin de la espera
        context.app.$eventBus().$emit('loading', false)
        // se genera un error arbitrario
        const errorLoadingMessage = "le serveur n'a pas répondu assez vite"
        // finalización con éxito
        resolve({ showErrorLoading: true, errorLoadingMessage })
        // registro
        console.log('[page2 asyncData finished]')
      }, 5000)
    })
  },
  // ciclo de vida
  beforeCreate() {
    console.log('[page2 beforeCreate]')
  },
  created() {
    console.log('[page2 created]')
  },
  beforeMount() {
    console.log('[page2 beforeMount]')
  },
  mounted() {
    console.log('[page2 mounted]')
    // cliente
    if (this.showErrorLoading) {
      console.log('[page2 mounted, showErrorLoading=true]')
      this.$eventBus().$emit('errorLoading', true, this.errorLoadingMessage)
    }
  }
}
</script>

De nuevo, insertamos una función [asyncData] en el código de la página y, al igual que [index], [page2] generará un error que, en esta ocasión, gestionaremos de forma diferente.

  • Línea 44: tanto el servidor como el cliente completan la promesa con éxito devolviendo el resultado [{ showErrorLoading: true, errorLoadingMessage }]. Sabemos que esto tendrá como efecto incluir las propiedades [showerrorLoading, errorLoadingMessage] en las propiedades [data] de la página y que el cliente recibirá dichas propiedades;
  • líneas 60-67: sabemos que la función [mounted] solo la ejecuta el cliente;
  • línea 63: el cliente comprueba si se ha establecido la propiedad [showErrorLoading] (por el servidor o por el cliente, según el caso). Si es así, emite el evento [‘errorLoading’] (línea 65) para que la página [default] muestre el mensaje de error [this.errorLoadingMessage]. Al final, el servidor envía una página sin que se muestre ningún mensaje de error. Este lo muestra el cliente en el último momento, cuando la página se «carga»;

14.6. Exécution

14.6.1. [nuxt.config]

El archivo de ejecución [nuxt.config.js] es el siguiente:


export default {
  mode: 'universal',
  /*
   ** Headers of the page
   */
  head: {
    title: 'Introduction à [nuxt.js]',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      {
        hid: 'description',
        name: 'description',
        content: 'ssr routing loading asyncdata middleware plugins store'
      }
    ],
    link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
  },
  /*
   ** Customize the progress-bar color
   */
  loading: false,

  /*
   ** Global CSS
   */
  css: [],
  /*
   ** Plugins to load before mounting the App
   */
  plugins: [{ src: '@/plugins/event-bus' }],
  /*
   ** Nuxt.js dev-modules
   */
  buildModules: [
    // Doc: https://github.com/nuxt-community/eslint-module
    '@nuxtjs/eslint-module'
  ],
  /*
   ** Nuxt.js modules
   */
  modules: [
    // Doc: https://bootstrap-vue.js.org
    'bootstrap-vue/nuxt',
    // Doc: https://axios.nuxtjs.org/usage
    '@nuxtjs/axios'
  ],
  /*
   ** Axios module configuration
   ** See https://axios.nuxtjs.org/options
   */
  axios: {},
  /*
   ** Build configuration
   */
  build: {
    /*
     ** You can extend webpack config here
     */
    extend(config, ctx) {}
  },
  // directorio del código fuente
  srcDir: 'nuxt-11',
  // enrutador
  router: {
    // raíz de la aplicación URL
    base: '/nuxt-11/'
  },
  // servidor
  server: {
    // puerto de servicio, 3000 por defecto
    port: 81,
    // direcciones de red en las que se escucha; por defecto, localhost: 127.0.0.1
    // 0.0.0.0 = todas las direcciones de red del equipo
    host: 'localhost'
  }
}
  • línea 22: se establece la propiedad [loading] en [false] para que [nuxt] no utilice su imagen de espera por defecto;
  • línea 31: el complemento que define el bus de eventos;

14.6.2. L, una página [index] ejecutada por el servidor

Solicitamos la página [index] al servidor (escribimos URL [http://localhost:81/nuxt-11/] a mano). La página que muestra el navegador del cliente es la siguiente:

Image

Los registros son los siguientes:

Image

  • en [3], se ve que el servidor envía la página [error.vue];
  • en [4], se observa que el cliente también muestra la página [error] con el mismo error que el servidor;
  • se puede observar que el método [mShowLoading] de la página [default] no se ha invocado en el lado del servidor, a pesar de que la página [index] había activado una espera. Este método se invoca al recibir un evento y, al parecer, la gestión de eventos no está implementada en el servidor;

Analicemos el código fuente de la página recibida por el navegador del cliente:


<!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-11/">
  <link rel="preload" href="/nuxt-11/_nuxt/runtime.js" as="script">
  <link rel="preload" href="/nuxt-11/_nuxt/commons.app.js" as="script">
  <link rel="preload" href="/nuxt-11/_nuxt/vendors.app.js" as="script">
  <link rel="preload" href="/nuxt-11/_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-11] : personnalisation de l'attente, gestion des erreurs</h4>
              </div>
            <div>
              <div class="row">
                <div class="col-2">
                  <ul class="nav flex-column">
                    <li class="nav-item">
                      <a href="/nuxt-11/" target="_self" class="nav-link active nuxt-link-active">
                        Home
                      </a>
                    </li>
                    <li class="nav-item">
                      <a href="/nuxt-11/page1" target="_self" class="nav-link">
                        Page 1
                      </a>
                    </li>
                    <li class="nav-item">
                      <a href="/nuxt-11/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" align="center" class="alert alert-danger">
                <h4>L'erreur suivante s'est produite : {&quot;statusCode&quot;:500,&quot;message&quot;:&quot;le serveur n'a pas répondu assez vite&quot;}</h4>
                    </div>
                </div>
              </div>
            </div>  
          </div>
        </div>
      </div>
    </div>
  </div>
  <script>window.__NUXT__ = (function (a, b, c, d) {
  d.statusCode = 500; d.message = "le serveur n'a pas répondu assez vite";
  return {
    layout: "default", data: [d], error: d, serverRendered: true,
    logs: [
      { date: new Date(1575047424168), args: ["[event-bus créé]"], type: a, level: b, tag: c },
      { date: new Date(1575047424175), args: ["[page1 asyncData started]"], type: a, level: b, tag: c },
      { date: new Date(1575047429455), args: ["[page1 asyncData finished]"], type: a, level: b, tag: c },
      { date: new Date(1575047429515), args: ["[default beforeCreate]"], type: a, level: b, tag: c },
      { date: new Date(1575047429675), args: ["[default created]"], type: a, level: b, tag: c },
      { date: new Date(1575047430157), args: ["[error beforeCreate]"], type: a, level: b, tag: c },
      { date: new Date(1575047430246), args: ["[error created, error=]", "{ statusCode: 500,\n  message: 'le serveur n\\'a pas répondu assez vite' }"], type: a, level: b, tag: c }]
  }
    }("log", 2, "", {}));</script>
  <script src="/nuxt-11/_nuxt/runtime.js" defer></script>
  <script src="/nuxt-11/_nuxt/commons.app.js" defer></script>
  <script src="/nuxt-11/_nuxt/vendors.app.js" defer></script>
  <script src="/nuxt-11/_nuxt/app.js" defer></script>
</body>
</html>
  • línea 57: vemos que el servidor ha enviado un objeto [d] que representa el error que se ha producido en el lado del servidor;
  • línea 59: se observa una propiedad [error] cuyo valor es el objeto [d]. Podemos suponer que es la presencia de la propiedad [error] en la página enviada por el servidor lo que hace que los scripts del cliente muestren la página [error.vue] con el error [error];

14.6.3. La página [page1] ejecutada por el servidor

Introducimos manualmente URL [http://localhost:81/nuxt-11/page1]. Al cabo de 5 segundos, el navegador muestra la siguiente página:

Image

Los registros mostrados son los siguientes:

Image

  • en [1], los registros del servidor. Se puede observar que el método [mShowLoading] de la página [default] no se ha llamado;
  • en [2], los registros del cliente;

14.6.4. La página [page2] ejecutada por el servidor

Introducimos manualmente URL [http://localhost:81/nuxt-11/page2]. Al cabo de 5 segundos, el navegador muestra la siguiente página:

Image

Analicemos los registros que se muestran en el navegador:

Image

  • en [1], los registros del servidor. Recordemos que el servidor ha incluido las propiedades [showErrorLoading, errorLoadingMessage] en la página enviada al navegador del cliente. Sabemos que, entonces, estas propiedades se integrarán en los [data] de la página mostrada por el cliente
  • en [3], cuando se carga la página [page2], encuentra la propiedad [showErrorLoading] con el valor «verdadero». A continuación, envía un evento a la página [default] para que muestre el mensaje de error enviado por el servidor [4];

14.6.5. La página [index] ejecutada por el cliente

Ahora utilizamos los enlaces de navegación para mostrar las tres páginas. Todas las páginas mostradas por el cliente son idénticas a las mostradas por el servidor. La única diferencia es que cada vez se muestra la imagen de espera al finalizar los 5 segundos.

Empezamos por la página [index]. A continuación, se muestra la imagen de espera:

Image

y, tras 5 segundos, aparece la siguiente página:

Image

La página final es, por tanto, idéntica a la obtenida en el servidor.

Image

Recordemos la función [asyncData] de la página [index]:


asyncData(context) {
    // registro
    console.log('[page1 asyncData started]')
    // Inicio de la espera
    context.app.$eventBus().$emit('loading', true)
    // sin errores
    context.app.$eventBus().$emit('errorLoading', false)
    // se devuelve una promesa
    return new Promise(function(resolve, reject) {
      // se simula una función asíncrona
      setTimeout(function() {
        // fin de la espera
        context.app.$eventBus().$emit('loading', false)
        // registro
        console.log('[page1 asyncData finished]')
        // se devuelve un error
        reject(new Error("le serveur n'a pas répondu assez vite"))
      }, 5000)
    }).catch((e) => context.error({ statusCode: 500, message: e.message }))
}

Los registros del cliente son los siguientes:

Image

  • en [1], se inicia la función [asyncData];
  • en [2], se inicia la imagen de espera;
  • en [2-3], se observa que la página [default] ha recibido los eventos [loading, true], [2] y [errorLoading, false] enviados por la función [asyncData] de la página [index] (líneas 5 y 7);
  • en [4], fin de la espera. La página [default] ha recibido el evento [loading, false] enviado por la página [index] (línea 13);
  • en [5], la función [asyncData] ha finalizado su trabajo;
  • debido a que la función [asyncData] generó un error con [context.error] (línea 19), se muestra la página [error] [6];

14.6.6. La página [page1] ejecutada por el cliente

Tras una espera de 5 segundos, el cliente muestra la siguiente página:

Image

Recordemos el código de la función [asyncData] de [page1]:


asyncData(context) {
    // registro
    console.log('[page1 asyncData started]')
    // Inicio de la espera
    context.app.$eventBus().$emit('loading', true)
    // sin error
    context.app.$eventBus().$emit('errorLoading', false)
    // se devuelve una promesa
    return new Promise(function(resolve, reject) {
      // se simula una función asíncrona
      setTimeout(function() {
        // fin de la espera
        context.app.$eventBus().$emit('loading', false)
        // registro
        console.log('[page1 asyncData finished]')
        // se devuelve el resultado asíncrono: un número aleatorio aquí
        resolve({ result: Math.floor(Math.random() * Math.floor(100)) })
      }, 5000)
    })
},

Los registros son los siguientes:

Image

14.6.7. La página [page2] ejecutada por el cliente

Tras una espera de 5 segundos, el cliente muestra la siguiente página:

Image

Recordemos el código de las funciones [asyncData] y [mounted] de [page2]:


asyncData(context) {
    // registro
    console.log('[page2 asyncData started]')
    // inicio de la espera
    context.app.$eventBus().$emit('loading', true)
    // sin errores
    context.app.$eventBus().$emit('errorLoading', false)
    // se devuelve una promesa
    return new Promise(function(resolve, reject) {
      // se simula una función asíncrona
      setTimeout(function() {
        // fin de la espera
        context.app.$eventBus().$emit('loading', false)
        // se genera un error arbitrario
        const errorLoadingMessage = "le serveur n'a pas répondu assez vite"
        // finalización con éxito
        resolve({ showErrorLoading: true, errorLoadingMessage })
        // registro
        console.log('[page2 asyncData finished]')
      }, 5000)
    })
  }

mounted() {
    console.log('[page2 mounted]')
    // cliente
    if (this.showErrorLoading) {
      console.log('[page2 mounted, showErrorLoading=true]')
      this.$eventBus().$emit('errorLoading', true, this.errorLoadingMessage)
    }
}

Los registros son los siguientes:

Image

  • en [1], la página [default] recibió el evento [showErrorLoading, true] enviado por [page2] (línea 29), que le solicita que muestre el mensaje de error;