Skip to content

14. Esempio [nuxt-11]: personalizzazione dell’immagine di caricamento

Per impostazione predefinita, l’immagine di caricamento di [nuxt] è una barra di avanzamento. L’esempio [nuxt-11] mostra che è possibile sostituirla con una propria immagine di caricamento:

Image

L'esempio [nuxt-11] mostra inoltre come gestire gli errori di caricamento.

Image

L’esempio [nuxt-11] si ottiene inizialmente copiando l’esempio [nuxt-10]:

Image

In [1] aggiungeremo un plugin per il client il cui ruolo sarà quello di gestire gli eventi tra i componenti.

14.1. Il plugin [event-bus]

Il plugin [event-bus] verrà eseguito sia dal client che dal server, ma vedremo che non funziona sul lato server. Il suo codice è il seguente:


// si crea un bus di eventi tra le viste
import Vue from 'vue'
export default (context, inject) => {
  // il bus di eventi
  const eventBus = new Vue()
  // iniezione di una funzione [eventBus] nel contesto
  inject('eventBus', () => eventBus)
}
  • riga 5: il bus degli eventi è un'istanza della classe [Vue]. Infatti, questa classe dispone dei metodi per gestire gli eventi:
    • [$emit]: per emettere un evento;
    • [$on]: per ascoltare un evento specifico;

Questo bus di eventi gestirà un solo evento, [loading], che verrà utilizzato dalle pagine per avviare/interrompere l’animazione di attesa al termine di una funzione asincrona;

  • riga 7: si crea una funzione [$eventBus] (1° argomento) il cui ruolo sarà quello di restituire l’oggetto [eventBus] appena creato (2° argomento). Questa funzione viene inserita nel contesto affinché sia disponibile negli oggetti [context.app] e [this] delle pagine;

14.2. Il layout [default.vue]

Il layout [default.vue] si evolve come segue:


<template>
  <div class="container">
    <b-card>
      <!-- un messaggio -->
      <b-alert show variant="success" align="center">
        <h4>[nuxt-11] : personnalisation de l'attente, gestion des erreurs</h4>
      </b-alert>
      <!-- la vista corrente del routing -->
      <nuxt />
      <!-- caricamento in corso -->
      <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>
      <!-- errore di caricamento -->
      <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 di vita
  beforeCreate() {
    console.log('[default beforeCreate]')
  },
  created() {
    console.log('[default created]')
    // si ascolta l'evento [loading]
    this.$eventBus().$on('loading', this.mShowLoading)
    // così come l'evento [errorLoadingMessage]
    this.$eventBus().$on('errorLoading', this.mShowErrorLoading)
  },
  beforeMount() {
    console.log('[default beforeMount]')
  },
  mounted() {
    console.log('[default mounted]')
  },
  methods: {
    // gestione del caricamento
    mShowLoading(value) {
      console.log('[default mShowLoading], showLoading=', value)
      this.showLoading = value
    },
    // errore di caricamento
    mShowErrorLoading(value, errorLoadingMessage) {
      console.log('[default mShowErrorLoading], showErrorLoading=', value, 'errorLoadingMessage=', errorLoadingMessage)
      this.showErrorLoading = value
      this.errorLoadingMessage = errorLoadingMessage
    }
  }
}
</script>
  • righe 11-14: l’animazione di attesa. Viene visualizzata solo se la proprietà [showLoading] è vera (riga 29);
  • righe 16-18: il messaggio di errore relativo al caricamento. Viene visualizzato solo se la proprietà [showErrorLoading] (riga 30) è vera;
  • righe 29-30: al caricamento iniziale del componente, l’animazione di attesa e il messaggio di errore vengono nascosti;
  • righe 37-43: una volta creata, la pagina ascolta l’evento [loading] (1° argomento) sul bus di eventi creato dal plugin. Al suo ricevimento, fa eseguire il metodo [mShowLoading] delle righe 52-55 (2° argomento);
  • righe 52-55: il valore ricevuto dal metodo [mShowLoading] sarà un valore booleano true / false. Serve a mostrare / nascondere il messaggio di attesa;
  • righe 41-42: al momento della creazione, la pagina ascolta l’evento [errorLoading] (1° argomento) sul bus degli eventi creato dal plugin. Al ricevimento dell’evento, fa eseguire il metodo [mShowErrorLoading] delle righe 57-61 (2° argomento);
  • riga 57: il metodo [mShowErrorLoading] riceve due argomenti:
    • il primo argomento è un valore booleano (true/false) per mostrare o nascondere il messaggio di errore;
    • il secondo argomento è presente solo in caso di errore. Rappresenta il messaggio di errore da visualizzare;
  • i log delle righe 53 e 58 ci mostreranno che i metodi [showLoading] e [showErrorLoading] non vengono eseguiti sul lato server;

14.3. La pagina [page1]

Il codice della pagina [page1] si evolve come segue:


<!-- vista n. 1 -->
<template>
  <Layout :left="true" :right="true">
    <!-- navigazione -->
    <Navigation slot="left" />
    <!-- messaggio-->
    <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',
  // componenti utilizzati
  components: {
    Layout,
    Navigation
  },
  // dati asincroni
  asyncData(context) {
    // log
    console.log('[page1 asyncData started]')
    // inizio attesa
    context.app.$eventBus().$emit('loading', true)
    // nessun errore
    context.app.$eventBus().$emit('errorLoading', false)
    // si restituisce una promessa
    return new Promise(function(resolve, reject) {
      // si simula una funzione asincrona
      setTimeout(function() {
        // fine attesa
        context.app.$eventBus().$emit('loading', false)
        // log
        console.log('[page1 asyncData finished]')
        // si restituisce il risultato asincrono - un numero casuale in questo caso
        resolve({ result: Math.floor(Math.random() * Math.floor(100)) })
      }, 5000)
    })
  },

  // ciclo di vita
  beforeCreate() {
    console.log('[page1 beforeCreate]')
  },
  created() {
    console.log('[page1 created]')
  },
  beforeMount() {
    console.log('[page1 beforeMount]')
  },
  mounted() {
    console.log('[page1 mounted]')
  }
}
</script>
  • le modifiche avvengono nella funzione [asyncData] alle righe 26-47;
  • righe 29-30: prima che inizi la funzione asincrona, viene emesso l’evento [loading] destinato alle altre pagine dell’applicazione. Si ricorda che in [asyncData] non si ha accesso all’oggetto [this], che non è ancora stato creato. Si utilizza quindi il contesto ricevuto come argomento dalla funzione [asyncData] (riga 26);
  • riga 30: si utilizza il bus degli eventi per segnalare che il caricamento sta per iniziare;
  • riga 38: si utilizza il bus degli eventi per segnalare che il caricamento è terminato;

Nota: durante l’esecuzione, quando la pagina [page1] viene richiesta al server, l’immagine di caricamento non viene visualizzata. Nei log si nota che, lato server, il metodo [default.mShowLoading] non viene chiamato. In ogni caso, visualizzare l’immagine di attesa non ha senso quando la pagina viene richiesta al server. Quest’ultimo invia la pagina al browser client solo una volta terminata la funzione [asyncData]. L’immagine di attesa è quindi superflua. Ciò vale per tutte le pagine dell’applicazione richieste direttamente al server.

14.4. La pagina [index]

Il codice della pagina [index] è il seguente:


<!-- pagina principale -->
<template>
  <Layout :left="true" :right="true">
    <!-- navigazione -->
    <Navigation slot="left" />
    <!-- messaggio-->
    <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',
  // componenti utilizzati
  components: {
    Layout,
    Navigation
  },
  // dati asincroni
  asyncData(context) {
    // log
    console.log('[page1 asyncData started]')
    // inizio attesa
    context.app.$eventBus().$emit('loading', true)
    // nessun errore
    context.app.$eventBus().$emit('errorLoading', false)
    // si restituisce una promessa
    return new Promise(function(resolve, reject) {
      // si simula una funzione asincrona
      setTimeout(function() {
        // fine attesa
        context.app.$eventBus().$emit('loading', false)
        // log
        console.log('[page1 asyncData finished]')
        // si restituisce un errore
        reject(new Error("le serveur n'a pas répondu assez vite"))
      }, 5000)
    }).catch((e) => context.error({ statusCode: 500, message: e.message }))
  },
  // ciclo di vita
  beforeCreate() {
    console.log('[home beforeCreate]')
  },
  created() {
    console.log('[home created]')
  },
  beforeMount() {
    console.log('[home beforeMount]')
  },
  mounted() {
    console.log('[home mounted]')
    // nessun errore
    this.$eventBus().$emit('errorLoading', false)
  }
}
</script>
  • righe 30-49: la funzione [asyncData] è identica a quella della pagina [page1], tranne che per un dettaglio: alla riga 46, la funzione asincrona viene terminata in caso di errore (utilizzo del metodo [reject]);
  • riga 46: il parametro della funzione [reject] è un’istanza della classe [Error]. Il parametro del costruttore [Error] è il messaggio di errore;
  • riga 48: questo errore viene intercettato dal metodo [catch] della classe [Promise], che riceve l’errore come parametro. Si utilizza quindi la funzione [context.error] per segnalare l’errore. Il parametro della funzione [context.error] è un oggetto che in questo caso presenta due proprietà:
    • [statusCode]: un codice di errore HTTP;
    • [message]: un messaggio di errore;

Sia che [asyncData] venga eseguita dal client o dal server, in caso di errore [context.error], [nuxt] visualizza la pagina [layouts / error.vue]:

Image

Sebbene si tratti di una pagina, la pagina [error.vue] viene cercata nella cartella [layouts] (forse per evitare che venga inclusa nei percorsi dell’applicazione?). In questo caso, la pagina [error.vue] è la seguente:


<!-- definizione HTML della vista -->
<template>
  <!-- impaginazione -->
  <Layout :left="true" :right="true">
    <!-- avviso nella colonna di destra -->
    <template slot="right">
      <!-- messaggio su sfondo giallo -->
      <b-alert show variant="danger" align="center">
        <h4>L'erreur suivante s'est produite : {{ JSON.stringify(error) }}</h4>
      </b-alert>
    </template>
    <!-- menu di navigazione nella colonna di sinistra -->
    <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',
  // componenti utilizzati
  components: {
    Layout,
    Navigation
  },
  // proprietà [props]
  props: { error: { type: Object, default: () => 'waiting ...' } },
  // ciclo di vita
  beforeCreate() {
    // client e server
    console.log('[error beforeCreate]')
  },
  created() {
    // client e server
    console.log('[error created, error=]', this.error)
  },
  beforeMount() {
    // solo client
    console.log('[error beforeMount]')
  },
  mounted() {
    // solo client
    console.log('[error mounted]')
  }
}
</script>

Quando [nuxt] visualizza la pagina [error.vue], le passa come proprietà [props] l’errore che si è verificato (riga 33). Se l’errore è stato causato da [context.error(objet1)], la proprietà [props] della pagina [error.vue] avrà il valore [objet1]. La documentazione relativa a [nuxt] indica che [objet1] deve avere almeno gli attributi di [statusCode, message]. La riga 9 visualizza la stringa jSON dell’oggetto [objet1] ricevuto.

14.5. La pagina [page2]

La pagina [page2] mostra un altro modo di gestire l’errore:

  • in [page1], l’errore viene visualizzato in una pagina separata, [error.vue];
  • in [page2], l’errore verrà visualizzato nella pagina [page2] che ha causato l’errore;

Il codice di [page2] è il seguente:


<!-- vista n. 2 -->
<template>
  <Layout :left="true" :right="true">
    <!-- navigazione -->
    <Navigation slot="left" />
    <!-- messaggio -->
    <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',
  // componenti utilizzati
  components: {
    Layout,
    Navigation
  },
  // dati asincroni
  asyncData(context) {
    // log
    console.log('[page2 asyncData started]')
    // inizio attesa
    context.app.$eventBus().$emit('loading', true)
    // nessun errore
    context.app.$eventBus().$emit('errorLoading', false)
    // si restituisce una promessa
    return new Promise(function(resolve, reject) {
      // si simula una funzione asincrona
      setTimeout(function() {
        // fine attesa
        context.app.$eventBus().$emit('loading', false)
        // si genera un errore arbitrario
        const errorLoadingMessage = "le serveur n'a pas répondu assez vite"
        // fine con esito positivo
        resolve({ showErrorLoading: true, errorLoadingMessage })
        // log
        console.log('[page2 asyncData finished]')
      }, 5000)
    })
  },
  // ciclo di vita
  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>

Ancora una volta, si inserisce una funzione [asyncData] nel codice della pagina e, come nel caso di [index], [page2] genererà un errore che questa volta verrà gestito in modo diverso.

  • riga 44: sia il server che il client chiudono la promessa con esito positivo restituendo il risultato [{ showErrorLoading: true, errorLoadingMessage }]. Sappiamo che ciò avrà l’effetto di includere le proprietà [showerrorLoading, errorLoadingMessage] nelle proprietà [data] della pagina e che il client riceverà tali proprietà;
  • righe 60-67: sappiamo che la funzione [mounted] viene eseguita solo dal client;
  • riga 63: il client verifica se la proprietà [showErrorLoading] è stata impostata (dal server o dal client, a seconda dei casi). In caso affermativo, emette l’evento [‘errorLoading’] (riga 65) affinché la pagina [default] visualizzi il messaggio di errore [this.errorLoadingMessage]. Alla fine, il server invia una pagina senza alcun messaggio di errore visualizzato. Quest’ultimo viene visualizzato all’ultimo momento dal client quando la pagina viene «caricata»;

14.6. Exécution

14.6.1. [nuxt.config]

Il file di esecuzione [nuxt.config.js] è il seguente:


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: [
    // Documentazione: 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) {}
  },
  // directory del codice sorgente
  srcDir: 'nuxt-11',
  // router
  router: {
    // radice dell'applicazione URL
    base: '/nuxt-11/'
  },
  // server
  server: {
    // porta di servizio, 3000 per impostazione predefinita
    port: 81,
    // indirizzi di rete in ascolto, per impostazione predefinita localhost: 127.0.0.1
    // 0.0.0.0 = tutti gli indirizzi di rete del computer
    host: 'localhost'
  }
}
  • riga 22: si imposta la proprietà [loading] su [false] affinché [nuxt] non utilizzi la propria immagine di caricamento predefinita;
  • riga 31: il plugin che definisce il bus degli eventi;

14.6.2. L: pagina [index] eseguita dal server

Richiediamo la pagina [index] al server (digitando manualmente URL [http://localhost:81/nuxt-11/]). La pagina visualizzata dal browser client è la seguente:

Image

I log sono i seguenti:

Image

  • in [3], si vede che il server invia la pagina [error.vue];
  • in [4], si vede che anche il client visualizza la pagina [error] con lo stesso errore del server;
  • si può notare che il metodo [mShowLoading] della pagina [default] non è stato chiamato lato server, nonostante la pagina [index] avesse attivato un'attesa. Questo metodo viene chiamato alla ricezione di un evento e, a quanto pare, la gestione degli eventi non è implementata sul lato server;

Esaminiamo il codice sorgente della pagina ricevuta dal browser client:


<!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>
  • riga 57: si vede che il server ha inviato un oggetto [d] che rappresenta l’errore verificatosi sul lato server;
  • riga 59: si nota una proprietà [error] il cui valore è l'oggetto [d]. Si può ipotizzare che sia la presenza della proprietà [error] nella pagina inviata dal server a far sì che gli script client visualizzino la pagina [error.vue] con l’errore [error];

14.6.3. La pagina [page1] eseguita dal server

Si digita manualmente URL [http://localhost:81/nuxt-11/page1]. Dopo 5 secondi, il browser visualizza la pagina seguente:

Image

I log visualizzati sono i seguenti:

Image

  • in [1], i log del server. Si può notare che il metodo [mShowLoading] della pagina [default] non è stato chiamato;
  • in [2], i log del client;

14.6.4. La pagina [page2] eseguita dal server

Digitiamo manualmente URL [http://localhost:81/nuxt-11/page2]. Dopo 5 secondi, il browser visualizza la pagina seguente:

Image

Esaminiamo i log visualizzati nel browser:

Image

  • in [1], i log del server. Ricordiamo che il server ha inserito le proprietà [showErrorLoading, errorLoadingMessage] nella pagina inviata al browser client. Sappiamo quindi che queste proprietà verranno integrate nei [data] della pagina visualizzata dal client
  • in [3]; quando la pagina [page2] viene caricata, rileva che la proprietà [showErrorLoading] è impostata su vero. A quel punto invia un evento alla pagina [default], affinché questa visualizzi il messaggio di errore inviato dal server [4];

14.6.5. La pagina [index] eseguita dal client

Ora si utilizzano i link di navigazione per visualizzare le tre pagine. Tutte le pagine visualizzate dal client sono identiche a quelle visualizzate dal server. L’unica differenza è che ogni volta viene visualizzata l’immagine di attesa al termine dei 5 secondi.

Si inizia con la pagina [index]. Viene quindi visualizzata l’immagine di attesa:

Image

poi, dopo 5 secondi, si ottiene la pagina seguente:

Image

La pagina finale è quindi identica a quella ottenuta sul lato server.

Image

Ricordiamo la funzione [asyncData] della pagina [index]:


asyncData(context) {
    // log
    console.log('[page1 asyncData started]')
    // inizio attesa
    context.app.$eventBus().$emit('loading', true)
    // nessun errore
    context.app.$eventBus().$emit('errorLoading', false)
    // si restituisce una promessa
    return new Promise(function(resolve, reject) {
      // si simula una funzione asincrona
      setTimeout(function() {
        // fine attesa
        context.app.$eventBus().$emit('loading', false)
        // log
        console.log('[page1 asyncData finished]')
        // si restituisce un errore
        reject(new Error("le serveur n'a pas répondu assez vite"))
      }, 5000)
    }).catch((e) => context.error({ statusCode: 500, message: e.message }))
}

I log del client sono i seguenti:

Image

  • in [1], viene avviata la funzione [asyncData];
  • in [2], viene avviata l'immagine di attesa;
  • in [2-3], si nota che la pagina [default] ha ricevuto gli eventi [loading, true], [2] e [errorLoading, false] inviati dalla funzione [asyncData] della pagina [index] (righe 5 e 7);
  • in [4], fine dell’attesa. La pagina [default] ha ricevuto l’evento [loading, false] inviato dalla pagina [index] (riga 13);
  • in [5], la funzione [asyncData] ha terminato il proprio lavoro;
  • poiché la funzione [asyncData] ha generato un errore con [context.error] (riga 19), viene visualizzata la pagina [error] [6];

14.6.6. La pagina [page1] eseguita dal client

Dopo un'attesa di 5 secondi, il client visualizza la pagina seguente:

Image

Ricordiamo il codice della funzione [asyncData] da [page1]:


asyncData(context) {
    // log
    console.log('[page1 asyncData started]')
    // inizio attesa
    context.app.$eventBus().$emit('loading', true)
    // nessun errore
    context.app.$eventBus().$emit('errorLoading', false)
    // viene restituita una promessa
    return new Promise(function(resolve, reject) {
      // si simula una funzione asincrona
      setTimeout(function() {
        // fine attesa
        context.app.$eventBus().$emit('loading', false)
        // log
        console.log('[page1 asyncData finished]')
        // si restituisce il risultato asincrono - un numero casuale in questo caso
        resolve({ result: Math.floor(Math.random() * Math.floor(100)) })
      }, 5000)
    })
},

I log sono i seguenti:

Image

14.6.7. La pagina [page2] eseguita dal client

Dopo un'attesa di 5 secondi, il client visualizza la pagina seguente:

Image

Ricordiamo il codice delle funzioni [asyncData] e [mounted] di [page2]:


asyncData(context) {
    // log
    console.log('[page2 asyncData started]')
    // inizio attesa
    context.app.$eventBus().$emit('loading', true)
    // nessun errore
    context.app.$eventBus().$emit('errorLoading', false)
    // si restituisce una promessa
    return new Promise(function(resolve, reject) {
      // si simula una funzione asincrona
      setTimeout(function() {
        // fine attesa
        context.app.$eventBus().$emit('loading', false)
        // si genera un errore arbitrario
        const errorLoadingMessage = "le serveur n'a pas répondu assez vite"
        // fine con esito positivo
        resolve({ showErrorLoading: true, errorLoadingMessage })
        // log
        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)
    }
}

I log sono i seguenti:

Image

  • in [1], la pagina [default] ha ricevuto l’evento [showErrorLoading, true] inviato da [page2] (riga 29) che le richiede di visualizzare il messaggio di errore;