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 reemplazar por una imagen de espera propia:

Image

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

Image

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

Image

Vamos a agregar 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] será ejecutado tanto por el cliente como por el servidor, pero veremos que no funciona del 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 cuenta con los métodos para gestionar eventos:
    • [$emit]: para emitir un evento;
    • [$on]: para escuchar un evento específico;

Este bus de eventos solo manejará 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>
      <!-- la 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: al crearse, 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 (verdadero/falso) 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 debe 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] cambia 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 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 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>
  • las modificaciones se realizan en la función [asyncData], en las líneas 26 a 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], ya 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 está a punto de 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, del 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 solo envía la página al navegador del cliente una vez que la función [asyncData] ha finalizado. La imagen de espera es 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 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 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 error (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;

Ya sea que [asyncData] sea ejecutada por el cliente o por 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?). Aquí, 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 produjo (línea 33). Si el error fue provocado por [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 manejar el error:

  • en [page1], el error se muestra en una página separada, [error.vue];
  • en [page2], el error se mostrará en la página [page2] que provocó el error;

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 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)
        // se genera un error arbitrario
        const errorLoadingMessage = "le serveur n'a pas répondu assez vite"
        // finalización exitosa
        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, manejaremos de manera 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á estas propiedades;
  • líneas 60-67: sabemos que la función [mounted] solo la ejecuta el cliente;
  • línea 63: el cliente verifica si se ha establecido la propiedad [showErrorLoading] (ya sea 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 es mostrado en el último momento por el cliente 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 escucha, por defecto localhost: 127.0.0.1
    // 0.0.0.0 = todas las direcciones de red de la máquina
    host: 'localhost'
  }
}
  • línea 22: se establece la propiedad [loading] en [false] para que [nuxt] no utilice su imagen de espera predeterminada;
  • línea 31: el complemento que define el bus de eventos;

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

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

Image

Los registros son los siguientes:

Image

  • en [3], se observa 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 llamado del 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, aparentemente, la gestión de eventos no está implementada en el lado del 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: se observa que el servidor envió un objeto [d] que representa el error que ocurrió del 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

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

Image

Los registros que se muestran 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

Tecleamos 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 incluyó 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 que ve el cliente
  • en [3]; cuando se carga la página [page2], encuentra la propiedad [showErrorLoading] con 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 que muestra el cliente son idénticas a las que muestra el servidor. La única diferencia es que cada vez se muestra la imagen de espera al finalizar los 5 segundos.

Comenzamos con la página [index]. En ese momento se muestra la imagen de espera:

Image

y, al cabo de 5 segundos, aparece la siguiente página:

Image

La página final es, por lo tanto, idéntica a la que se obtiene del lado del servidor.

Image

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


asyncData(context) {
    // registro
    console.log('[page1 asyncData started]')
    // inicio de 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] recibió el evento [loading, false] enviado por la página [index] (línea 13);
  • en [5], la función [asyncData] terminó 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 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 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 exitosa
        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;