Skip to content

14. Beispiel [nuxt-11]: Anpassung des Ladebildes

Standardmäßig ist das Ladebild von [nuxt] ein Fortschrittsbalken. Das Beispiel [nuxt-11] zeigt, dass man es durch ein eigenes Ladebild ersetzen kann:

Image

Das Beispiel [nuxt-11] zeigt außerdem, wie man Ladefehler behandelt.

Image

Das Beispiel [nuxt-11] wird zunächst durch Kopieren des Beispiels [nuxt-10] erstellt:

Image

Wir werden in [1] ein Plugin für den Client hinzufügen, dessen Aufgabe darin besteht, Ereignisse zwischen Komponenten zu verwalten.

14.1. Das Plugin [event-bus]

Das Plugin [event-bus] wird sowohl vom Client als auch vom Server ausgeführt, aber wir werden sehen, dass es serverseitig nicht funktioniert. Sein Code lautet wie folgt:


// Es wird ein Ereignisbus zwischen den Ansichten erstellt
import Vue from 'vue'
export default (context, inject) => {
  // der Ereignisbus
  const eventBus = new Vue()
  // Einspeisung einer Funktion [eventBus] in den Kontext
  inject('eventBus', () => eventBus)
}
  • Zeile 5: Der Ereignisbus ist eine Instanz der Klasse [Vue]. Diese verfügt nämlich über Methoden zur Verwaltung von Ereignissen:
    • [$emit]: zum Auslösen eines Ereignisses;
    • [$on]: zum Abhören eines bestimmten Ereignisses;

Dieser Ereignisbus verwaltet nur ein einziges Ereignis, [loading], das von den Seiten verwendet wird, um die Animation zum Anzeigen des Wartestatus bis zum Ende einer asynchronen Funktion zu starten bzw. zu stoppen;

  • Zeile 7: Es wird eine Funktion [$eventBus] (1. Argument) erstellt, deren Aufgabe es ist, das soeben erstellte Objekt [eventBus] (2. Argument) zurückzugeben. Diese Funktion wird in den Kontext eingefügt, damit sie in den Objekten [context.app] und [this] der Seiten verfügbar ist;

14.2. Das Layout [default.vue]

Das Layout [default.vue] entwickelt sich wie folgt:


<template>
  <div class="container">
    <b-card>
      <!-- eine Nachricht -->
      <b-alert show variant="success" align="center">
        <h4>[nuxt-11] : personnalisation de l'attente, gestion des erreurs</h4>
      </b-alert>
      <!-- die aktuelle Routing-Ansicht -->
      <nuxt />
      <!-- wird geladen -->
      <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>
      <!-- Ladefehler -->
      <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
    }
  },
  // Lebenszyklus
  beforeCreate() {
    console.log('[default beforeCreate]')
  },
  created() {
    console.log('[default created]')
    // Das Ereignis [loading] wird abgehört
    this.$eventBus().$on('loading', this.mShowLoading)
    // sowie das Ereignis [errorLoadingMessage]
    this.$eventBus().$on('errorLoading', this.mShowErrorLoading)
  },
  beforeMount() {
    console.log('[default beforeMount]')
  },
  mounted() {
    console.log('[default mounted]')
  },
  methods: {
    // Ladungsmanagement
    mShowLoading(value) {
      console.log('[default mShowLoading], showLoading=', value)
      this.showLoading = value
    },
    // Ladefehler
    mShowErrorLoading(value, errorLoadingMessage) {
      console.log('[default mShowErrorLoading], showErrorLoading=', value, 'errorLoadingMessage=', errorLoadingMessage)
      this.showErrorLoading = value
      this.errorLoadingMessage = errorLoadingMessage
    }
  }
}
</script>
  • Zeilen 11–14: die Ladeanimation. Sie wird nur angezeigt, wenn die Eigenschaft [showLoading] wahr ist (Zeile 29);
  • Zeilen 16–18: Die Fehlermeldung beim Laden. Sie wird nur angezeigt, wenn die Eigenschaft [showErrorLoading] (Zeile 30) wahr ist;
  • Zeilen 29–30: Beim ersten Laden der Komponente werden die Ladeanimation und die Fehlermeldung ausgeblendet;
  • Zeilen 37–43: Bei ihrer Erstellung überwacht die Seite das Ereignis [loading] (1. Argument) auf dem vom Plugin erstellten Ereignisbus. Bei dessen Empfang lässt sie die Methode [mShowLoading] aus den Zeilen 52–55 (2. Argument) ausführen;
  • Zeilen 52–55: Der von der Methode [mShowLoading] empfangene Wert ist ein boolescher Wert (true/false). Er dient dazu, die Wartemeldung ein- bzw. auszublenden;
  • Zeilen 41–42: Bei ihrer Erstellung überwacht die Seite das Ereignis [errorLoading] (1. Argument) auf dem vom Plugin erstellten Ereignisbus. Bei Empfang dieses Ereignisses lässt sie die Methode [mShowErrorLoading] aus den Zeilen 57–61 (2. Argument) ausführen;
  • Zeile 57: Die Methode [mShowErrorLoading] erhält zwei Argumente:
    • Das erste Argument ist ein boolescher Wert (true/false), um die Fehlermeldung anzuzeigen bzw. auszublenden;
    • das zweite Argument ist nur vorhanden, wenn ein Fehler aufgetreten ist. Es stellt die anzuzeigende Fehlermeldung dar;
  • Die Log-Einträge in den Zeilen 53 und 58 zeigen uns, dass die Methoden [showLoading] und [showErrorLoading] serverseitig nicht ausgeführt werden;

14.3. Die Seite [page1]

Der Code der Seite [page1] entwickelt sich wie folgt:


<!-- Ansicht Nr. 1 -->
<template>
  <Layout :left="true" :right="true">
    <!-- Navigation -->
    <Navigation slot="left" />
    <!-- Meldung-->
    <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',
  // verwendete Komponenten
  components: {
    Layout,
    Navigation
  },
  // asynchrone Daten
  asyncData(context) {
    // Protokoll
    console.log('[page1 asyncData started]')
    // Wartezeit beginnt
    context.app.$eventBus().$emit('loading', true)
    // kein Fehler
    context.app.$eventBus().$emit('errorLoading', false)
    // ein Versprechen wird zurückgegeben
    return new Promise(function(resolve, reject) {
      // eine asynchrone Funktion wird simuliert
      setTimeout(function() {
        // Wartezeit beendet
        context.app.$eventBus().$emit('loading', false)
        // Protokoll
        console.log('[page1 asyncData finished]')
        // das asynchrone Ergebnis wird zurückgegeben – hier eine Zufallszahl
        resolve({ result: Math.floor(Math.random() * Math.floor(100)) })
      }, 5000)
    })
  },

  // Lebenszyklus
  beforeCreate() {
    console.log('[page1 beforeCreate]')
  },
  created() {
    console.log('[page1 created]')
  },
  beforeMount() {
    console.log('[page1 beforeMount]')
  },
  mounted() {
    console.log('[page1 mounted]')
  }
}
</script>
  • Die Änderungen finden in der Funktion [asyncData] in den Zeilen 26–47 statt;
  • Zeilen 29–30: Bevor die asynchrone Funktion startet, wird das Ereignis [loading] an die anderen Seiten der Anwendung gesendet. Es sei daran erinnert, dass in [asyncData] noch kein Zugriff auf das noch nicht angelegte Objekt [this] besteht. Daher wird der Kontext verwendet, den die Funktion [asyncData] als Argument erhält (Zeile 26);
  • Zeile 30: Der Ereignisbus wird verwendet, um anzuzeigen, dass der Ladevorgang beginnt;
  • Zeile 38: Über den Ereignisbus wird gemeldet, dass der Ladevorgang abgeschlossen ist;

Hinweis: Bei der Ausführung wird das Ladebild nicht angezeigt, wenn die Seite [page1] vom Server angefordert wird. In den Protokollen ist zu sehen, dass serverseitig die Methode [default.mShowLoading] nicht aufgerufen wird. Ohnehin macht es keinen Sinn, das Ladebild zu sehen, wenn die Seite vom Server angefordert wird. Der Server sendet die Seite erst dann an den Client-Browser, wenn die Funktion [asyncData] abgeschlossen ist. Das Ladebild ist dann überflüssig. Dies gilt für alle Seiten der Anwendung, die direkt vom Server angefordert werden.

14.4. Die Seite [index]

Der Code der Seite [index] lautet wie folgt:


<!-- Hauptseite -->
<template>
  <Layout :left="true" :right="true">
    <!-- Navigation -->
    <Navigation slot="left" />
    <!-- Meldung-->
    <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',
  // verwendete Komponenten
  components: {
    Layout,
    Navigation
  },
  // asynchrone Daten
  asyncData(context) {
    // Protokoll
    console.log('[page1 asyncData started]')
    // Wartezeit beginnt
    context.app.$eventBus().$emit('loading', true)
    // kein Fehler
    context.app.$eventBus().$emit('errorLoading', false)
    // ein Versprechen wird zurückgegeben
    return new Promise(function(resolve, reject) {
      // eine asynchrone Funktion wird simuliert
      setTimeout(function() {
        // Wartezeit beendet
        context.app.$eventBus().$emit('loading', false)
        // Protokoll
        console.log('[page1 asyncData finished]')
        // Es wird ein Fehler zurückgegeben
        reject(new Error("le serveur n'a pas répondu assez vite"))
      }, 5000)
    }).catch((e) => context.error({ statusCode: 500, message: e.message }))
  },
  // Lebenszyklus
  beforeCreate() {
    console.log('[home beforeCreate]')
  },
  created() {
    console.log('[home created]')
  },
  beforeMount() {
    console.log('[home beforeMount]')
  },
  mounted() {
    console.log('[home mounted]')
    // kein Fehler
    this.$eventBus().$emit('errorLoading', false)
  }
}
</script>
  • Zeilen 30–49: Die Funktion [asyncData] ist bis auf ein Detail identisch mit der der Seite [page1]: In Zeile 46 wird die asynchrone Funktion bei einem Fehler beendet (Verwendung der Methode [reject]);
  • Zeile 46: Der Parameter der Funktion [reject] ist eine Instanz der Klasse [Error]. Der Parameter des Konstruktors [Error] ist die Fehlermeldung;
  • Zeile 48: Dieser Fehler wird von der Methode [catch] der Klasse [Promise] abgefangen, die den Fehler als Parameter erhält. Anschließend wird die Funktion [context.error] verwendet, um den Fehler zu melden. Der Parameter der Funktion [context.error] ist ein Objekt mit hier zwei Eigenschaften:
    • [statusCode]: ein Fehlercode HTTP;
    • [message]: eine Fehlermeldung;

Unabhängig davon, ob [asyncData] vom Client oder vom Server ausgeführt wird, zeigt [nuxt] im Falle eines Fehlers [context.error] die Seite [layouts / error.vue] an:

Image

Obwohl es sich um eine Seite handelt, wird die Seite [error.vue] im Ordner [layouts] gesucht (möglicherweise, um zu verhindern, dass sie in die Routen der Anwendung aufgenommen wird?). Hier lautet die Seite [error.vue] wie folgt:


<!-- Definition der Ansicht HTML -->
<template>
  <!-- Layout -->
  <Layout :left="true" :right="true">
    <!-- Warnung in der rechten Spalte -->
    <template slot="right">
      <!-- Meldung auf gelbem Hintergrund -->
      <b-alert show variant="danger" align="center">
        <h4>L'erreur suivante s'est produite : {{ JSON.stringify(error) }}</h4>
      </b-alert>
    </template>
    <!-- Navigationsmenü in der linken Spalte -->
    <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',
  // verwendete Komponenten
  components: {
    Layout,
    Navigation
  },
  // Eigenschaft [props]
  props: { error: { type: Object, default: () => 'waiting ...' } },
  // Lebenszyklus
  beforeCreate() {
    // Client und Server
    console.log('[error beforeCreate]')
  },
  created() {
    // Client und Server
    console.log('[error created, error=]', this.error)
  },
  beforeMount() {
    // nur Client
    console.log('[error beforeMount]')
  },
  mounted() {
    // nur Client
    console.log('[error mounted]')
  }
}
</script>

Wenn [nuxt] die Seite [error.vue] anzeigt, übergibt sie ihr als Eigenschaft [props] den aufgetretenen Fehler (Zeile 33). Wurde der Fehler durch [context.error(objet1)] verursacht, hat die Eigenschaft [props] der Seite [error.vue] den Wert [objet1]. Die Dokumentation zu [nuxt] gibt an, dass [objet1] mindestens die Attribute von [statusCode, message] aufweisen muss. In Zeile 9 wird die Zeichenfolge jSON des empfangenen Objekts [objet1] angezeigt.

14.5. Die Seite [page2]

Die Seite [page2] zeigt eine weitere Möglichkeit zur Fehlerbehandlung:

  • In [page1] wird der Fehler auf einer separaten Seite ([error.vue]) angezeigt;
  • in [page2] wird der Fehler auf der Seite [page2] angezeigt, die den Fehler verursacht hat;

Der Code für [page2] lautet wie folgt:


<!-- Ansicht Nr. 2 -->
<template>
  <Layout :left="true" :right="true">
    <!-- Navigation -->
    <Navigation slot="left" />
    <!-- Meldung -->
    <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',
  // verwendete Komponenten
  components: {
    Layout,
    Navigation
  },
  // asynchrone Daten
  asyncData(context) {
    // Protokoll
    console.log('[page2 asyncData started]')
    // Wartezeit beginnt
    context.app.$eventBus().$emit('loading', true)
    // kein Fehler
    context.app.$eventBus().$emit('errorLoading', false)
    // ein Versprechen wird zurückgegeben
    return new Promise(function(resolve, reject) {
      // eine asynchrone Funktion wird simuliert
      setTimeout(function() {
        // Wartezeit beendet
        context.app.$eventBus().$emit('loading', false)
        // Es wird willkürlich ein Fehler erzeugt
        const errorLoadingMessage = "le serveur n'a pas répondu assez vite"
        // Erfolgreich beendet
        resolve({ showErrorLoading: true, errorLoadingMessage })
        // Protokoll
        console.log('[page2 asyncData finished]')
      }, 5000)
    })
  },
  // Lebenszyklus
  beforeCreate() {
    console.log('[page2 beforeCreate]')
  },
  created() {
    console.log('[page2 created]')
  },
  beforeMount() {
    console.log('[page2 beforeMount]')
  },
  mounted() {
    console.log('[page2 mounted]')
    // Client
    if (this.showErrorLoading) {
      console.log('[page2 mounted, showErrorLoading=true]')
      this.$eventBus().$emit('errorLoading', true, this.errorLoadingMessage)
    }
  }
}
</script>

Erneut fügen wir eine Funktion [asyncData] in den Code der Seite ein, und wie bei [index] wird [page2] einen Fehler generieren, den wir dieses Mal anders behandeln werden.

  • Zeile 44: Sowohl der Server als auch der Client schließen das Promise erfolgreich ab und geben das Ergebnis [{ showErrorLoading: true, errorLoadingMessage }] zurück. Wir wissen, dass dies dazu führt, dass die Eigenschaften [showerrorLoading, errorLoadingMessage] in die Eigenschaften [data] der Seite aufgenommen werden und dass der Client diese Eigenschaften erhält;
  • Zeilen 60–67: Es ist bekannt, dass die Funktion [mounted] nur vom Client ausgeführt wird;
  • Zeile 63: Der Client prüft, ob die Eigenschaft [showErrorLoading] gesetzt wurde (je nach Fall durch den Server oder den Client). Wenn ja, löst er das Ereignis [‘errorLoading’] (Zeile 65) aus, damit die Seite [default] die Fehlermeldung [this.errorLoadingMessage] anzeigt. Letztendlich sendet der Server eine Seite, auf der keine Fehlermeldung angezeigt wird. Diese wird erst im letzten Moment vom Client angezeigt, wenn die Seite „geladen“ wird;

14.6. Exécution

14.6.1. [nuxt.config]

Die Ausführungsdatei [nuxt.config.js] lautet wie folgt:


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: [
    // Dok: https://github.com/nuxt-community/eslint-module
    '@nuxtjs/eslint-module'
  ],
  /*
   ** Nuxt.js modules
   */
  modules: [
    // Dok.: https://bootstrap-vue.js.org
    'bootstrap-vue/nuxt',
    // Dok.: 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) {}
  },
  // Quellcode-Verzeichnis
  srcDir: 'nuxt-11',
  // Router
  router: {
    // Stammverzeichnis der Anwendung URL
    base: '/nuxt-11/'
  },
  // Server
  server: {
    // Dienstport, standardmäßig 3000
    port: 81,
    // abgehörte Netzwerkadressen, standardmäßig localhost: 127.0.0.1
    // 0.0.0.0 = alle Netzwerkadressen des Rechners
    host: 'localhost'
  }
}
  • Zeile 22: Die Eigenschaft [loading] wird auf [false] gesetzt, damit [nuxt] nicht sein Standard-Ladebild verwendet;
  • Zeile 31: Das Plugin, das den Ereignisbus definiert;

14.6.2. L – eine Seite [index], die vom Server ausgeführt wird

Rufen wir die Seite [index] vom Server ab (wir geben die URL URL manuell ein). Die vom Client-Browser angezeigte Seite sieht wie folgt aus:

Image

Die Protokolleinträge lauten wie folgt:

Image

  • In „[3]“ sieht man, dass der Server die Seite „[error.vue]“ sendet;
  • in [4] ist zu sehen, dass auch der Client die Seite [error] mit demselben Fehler wie der Server anzeigt;
  • Es fällt auf, dass die Methode [mShowLoading] der Seite [default] serverseitig nicht aufgerufen wurde, obwohl die Seite [index] eine Warteschleife aktiviert hatte. Diese Methode wird beim Empfang eines Ereignisses aufgerufen, und offenbar ist die Ereignisbehandlung serverseitig nicht implementiert;

Sehen wir uns den Quellcode der vom Client-Browser empfangenen Seite an:


<!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>
  • Zeile 57: Wir sehen, dass der Server ein Objekt [d] gesendet hat, das den auf der Serverseite aufgetretenen Fehler darstellt;
  • Zeile 59: Hier ist eine Eigenschaft [error] zu sehen, deren Wert das Objekt [d] ist. Man kann sich vorstellen, dass das Vorhandensein der Eigenschaft [error] in der vom Server gesendeten Seite dazu führt, dass die Client-Skripte die Seite [error.vue] mit dem Fehler [error] anzeigen;

14.6.3. Die vom Server ausgeführte Seite [page1]

Man gibt „URL [http://localhost:81/nuxt-11/page1]“ manuell ein. Nach 5 Sekunden zeigt der Browser die folgende Seite an:

Image

Die angezeigten Protokolle lauten wie folgt:

Image

  • in [1] die Server-Logs. Es ist zu erkennen, dass die Methode [mShowLoading] der Seite [default] nicht aufgerufen wurde;
  • in [2] die Client-Protokolle;

14.6.4. Die vom Server ausgeführte Seite [page2]

Wir geben die URL „URL [http://localhost:81/nuxt-11/page2]“ manuell ein. Nach 5 Sekunden zeigt der Browser die folgende Seite an:

Image

Sehen wir uns die im Browser angezeigten Protokolle an:

Image

  • in [1], die Server-Protokolle. Zur Erinnerung: Der Server hat die Eigenschaften [showErrorLoading, errorLoadingMessage] in die an den Client-Browser gesendete Seite eingefügt. Wir wissen, dass diese Eigenschaften dann in die [data] der vom Client angezeigten Seite integriert werden
  • in [3]: Wenn die Seite [page2] geladen wird, findet sie die Eigenschaft [showErrorLoading] mit dem Wert „true“. Sie sendet daraufhin ein Ereignis an die Seite [default], damit diese die vom Server [4] gesendete Fehlermeldung anzeigt;

14.6.5. Die vom Client ausgeführte Seite [index]

Nun werden die Navigationslinks verwendet, um die drei Seiten anzuzeigen. Alle vom Client angezeigten Seiten sind identisch mit denen, die vom Server angezeigt werden. Der einzige Unterschied besteht darin, dass jedes Mal das Ladebild für das Ende der 5 Sekunden angezeigt wird.

Wir beginnen mit der Seite [index]. Das Ladebild wird nun angezeigt:

Image

und nach 5 Sekunden erscheint die folgende Seite:

Image

Die endgültige Seite ist also identisch mit der auf der Serverseite angezeigten.

Image

Erinnern wir uns an die Funktion [asyncData] auf der Seite [index]:


asyncData(context) {
    // Protokoll
    console.log('[page1 asyncData started]')
    // Wartezeit beginnt
    context.app.$eventBus().$emit('loading', true)
    // kein Fehler
    context.app.$eventBus().$emit('errorLoading', false)
    // ein Versprechen wird zurückgegeben
    return new Promise(function(resolve, reject) {
      // eine asynchrone Funktion wird simuliert
      setTimeout(function() {
        // Wartezeit beendet
        context.app.$eventBus().$emit('loading', false)
        // Protokoll
        console.log('[page1 asyncData finished]')
        // Es wird ein Fehler zurückgegeben
        reject(new Error("le serveur n'a pas répondu assez vite"))
      }, 5000)
    }).catch((e) => context.error({ statusCode: 500, message: e.message }))
}

Die Client-Protokolle lauten wie folgt:

Image

  • In [1] wird die Funktion [asyncData] gestartet;
  • in [2] wird das Wartezahnrad gestartet;
  • bei [2-3] ist zu sehen, dass die Seite [default] die Ereignisse [loading, true], [2] und [errorLoading, false] empfangen hat, die von der Funktion [asyncData] der Seite [index] gesendet wurden (Zeilen 5 und 7);
  • in [4], Ende der Wartezeit. Die Seite [default] hat das Ereignis [loading, false] empfangen, das von der Seite [index] gesendet wurde (Zeile 13);
  • in [5] hat die Funktion [asyncData] ihre Arbeit beendet;
  • da die Funktion [asyncData] bei [context.error] einen Fehler verursacht hat (Zeile 19), wird die Seite [error] angezeigt: [6];

14.6.6. Die vom Client ausgeführte Seite [page1]

Nach einer Wartezeit von 5 Sekunden zeigt der Client die folgende Seite an:

Image

Zur Erinnerung: Der Code der Funktion [asyncData] aus [page1]:


asyncData(context) {
    // Protokoll
    console.log('[page1 asyncData started]')
    // Wartezeit beginnt
    context.app.$eventBus().$emit('loading', true)
    // kein Fehler
    context.app.$eventBus().$emit('errorLoading', false)
    // ein Versprechen wird zurückgegeben
    return new Promise(function(resolve, reject) {
      // eine asynchrone Funktion wird simuliert
      setTimeout(function() {
        // Wartezeit beendet
        context.app.$eventBus().$emit('loading', false)
        // Protokoll
        console.log('[page1 asyncData finished]')
        // das asynchrone Ergebnis wird zurückgegeben – hier eine Zufallszahl
        resolve({ result: Math.floor(Math.random() * Math.floor(100)) })
      }, 5000)
    })
},

Die Protokolle lauten wie folgt:

Image

14.6.7. Die vom Client ausgeführte Seite [page2]

Nach einer Wartezeit von 5 Sekunden zeigt der Client die folgende Seite an:

Image

Zur Erinnerung: Der Code der Funktionen [asyncData] und [mounted] aus [page2] lautet wie folgt:


asyncData(context) {
    // Protokoll
    console.log('[page2 asyncData started]')
    // Wartezeit beginnt
    context.app.$eventBus().$emit('loading', true)
    // kein Fehler
    context.app.$eventBus().$emit('errorLoading', false)
    // ein Promise wird zurückgegeben
    return new Promise(function(resolve, reject) {
      // eine asynchrone Funktion wird simuliert
      setTimeout(function() {
        // Wartezeit beendet
        context.app.$eventBus().$emit('loading', false)
        // Es wird willkürlich ein Fehler erzeugt
        const errorLoadingMessage = "le serveur n'a pas répondu assez vite"
        // Erfolgreich beendet
        resolve({ showErrorLoading: true, errorLoadingMessage })
        // Protokoll
        console.log('[page2 asyncData finished]')
      }, 5000)
    })
  }

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

Die Protokolle lauten wie folgt:

Image

  • In [1] hat die Seite [default] das von [page2] gesendete Ereignis [showErrorLoading, true] empfangen (Zeile 29), das sie auffordert, die Fehlermeldung anzuzeigen;