Skip to content

13. Beispiel [nuxt-10]: asyncData und „Loading“

Die Funktion [asyncData] auf einer Seite ermöglicht das asynchrone Laden von Daten, die häufig von externen Quellen stammen. [nuxt] wartet das Ende der Funktion [asyncData] ab, bevor der Lebenszyklus der Seite beginnt. Die Seite wird daher erst gerendert, wenn die externen Daten vorliegen. Sie wird sowohl vom Server als auch vom Client nach folgenden Regeln ausgeführt:

  • Wenn die Seite direkt vom Server angefordert wird, führt nur der Server die Funktion [asyncData] aus;
  • anschließend, bei der Navigation auf Seiten des Clients, führt nur der Client die Funktion [asyncData] aus;

Letztendlich führt nur einer der beiden – entweder der Client oder der Server – die Funktion aus. Wenn der Client die Funktion [asyncData] ausführt, zeigt [nuxt] zudem einen Fortschrittsbalken an, der konfiguriert werden kann.

Die Funktion [asyncData] ermöglicht es, Seiten mit ihren Daten an Suchmaschinen zu übermitteln, wodurch diese an Relevanz gewinnen.

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

Image

Nur die Seite [page1] wird weiterentwickelt.

13.1. Die Seite [page1]

Der Code der Seite [page1] lautet 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]')
    // ein Promise wird zurückgegeben
    return new Promise(function(resolve, reject) {
      // eine asynchrone Funktion wird simuliert
      setTimeout(function () {
        // Das Ergebnis wird asynchron zurückgegeben – hier eine Zufallszahl
        resolve({ result: Math.floor(Math.random() * Math.floor(100)) })
        // log
        console.log('[page1 asyncData finished]')
      }, 5000)
    })
  },

  // Lebenszyklus
  beforeCreate() {
    console.log('[page1 beforeCreate]')
  },
  created() {
    console.log('[page1 created]')
  },
  beforeMount() {
    console.log('[page1 beforeMount]')
  },
  mounted() {
    console.log('[page1 mounted]')
  }
}
</script>
  • Zeilen 26–39: die Funktion [asyncData]. Diese Funktion haben wir bereits behandelt (siehe Abschnitt „Link“). Sie wird vor dem Lebenszyklus der Seite ausgeführt. Aus diesem Grund kann das Schlüsselwort [this] in der Funktion nicht verwendet werden;
  • Zeile 30: Sie muss ein Promise [Promise] zurückgeben oder die async/await-Syntax verwenden;
  • Zeilen 32–37: Die asynchrone Funktion des Promises wird mit einer Wartezeit von 5 Sekunden simuliert (Zeile 37);
  • Zeile 34: Das Ergebnis der asynchronen Funktion wird in Form eines Objekts {result :...} zurückgegeben. Das von der Funktion [asyncData] zurückgegebene asynchrone Objekt wird in das Objekt [data] der Seite integriert. Deshalb ist das Objekt [result] in Zeile 7 der Vorlage verfügbar, obwohl auf der Seite kein Objekt [data] definiert wurde;

13.2. Konfiguration des Fortschrittsbalkens von [asyncData]

Wenn die Seite [page1] das Ziel einer Navigation innerhalb des Clients ist (Modus SPA), führt der Client die Funktion [asyncData] aus, und [nuxt] zeigt daraufhin einen Fortschrittsbalken an, den sie ausblendet, sobald die Funktion [asyncData] ihr Ergebnis zurückgegeben hat. Über die Eigenschaft [loading] der Datei [nuxt.config.js] lässt sich dieser Fortschrittsbalken konfigurieren:


loading: {
    color: 'blue',
    height: '5px',
    throttle: 200,
    continuous: true
},

Standardmäßig ist das Ladebild von [nuxt] ein Fortschrittsbalken, der sich über die gesamte Breite der Seite erstreckt. Dieser Balken hat eine Farbe und eine Dicke. Der farbige Balken wächst schrittweise von 0 % auf 100 % seiner Größe an, also je nach Wartezeit mehr oder weniger schnell.

  • Zeile 2: Legt die Farbe des Fortschrittsbalkens fest;
  • Zeile 3: Legt die Dicke des Balkens in Pixeln fest;
  • Zeile 4: [throttle] ist die Verzögerung in Millisekunden, bevor die Animation startet. Dadurch wird verhindert, dass ein Animationsbild angezeigt wird, wenn die Funktion [asyncData] ihr Ergebnis schnell liefert;
  • Zeile 5: [continuous] legt das Verhalten der Fortschrittsbalken-Animation fest. Standardmäßig wächst der Balken schrittweise von 0 % auf 100 % seiner Größe, je nach Wartezeit mehr oder weniger schnell. Mit [continuous:true] wächst der farbige Balken mit konstanter Geschwindigkeit von 0 auf 100 % seiner Größe und beginnt dann von vorne, solange die Funktion [asyncData] ihr Ergebnis noch nicht zurückgegeben hat;

13.3. Exécution

Starten wir die Anwendung und fordern wir dann manuell die Seite [page1] vom Server an:

Image

Die Protokolle lauten wie folgt:

Image

  • Man sieht, dass nur der Server [1] die Funktion [asyncData] ausgeführt hat, und zwar vor dem Seitenzyklus;

Betrachten wir nun die vom Server gesendete Seite (Quellcode):


<!doctype html>
<html data-n-head-ssr>
<head>
  <title>Introduction à [nuxt.js]</title>
  <meta data-n-head="ssr" charset="utf-8">
  <meta data-n-head="ssr" name="viewport" content="width=device-width, initial-scale=1">
  <meta data-n-head="ssr" data-hid="description" name="description" content="ssr routing loading asyncdata middleware plugins store">
  <link data-n-head="ssr" rel="icon" type="image/x-icon" href="/favicon.ico">
  <base href="/nuxt-10/">
  <link rel="preload" href="/nuxt-10/_nuxt/runtime.js" as="script">
  <link rel="preload" href="/nuxt-10/_nuxt/commons.app.js" as="script">
  <link rel="preload" href="/nuxt-10/_nuxt/vendors.app.js" as="script">
  <link rel="preload" href="/nuxt-10/_nuxt/app.js" as="script">
...
</head>
<body>
  <div data-server-rendered="true" id="__nuxt">
    <div id="__layout">
      <div class="container">
        <div class="card">
          <div class="card-body">
            <div role="alert" aria-live="polite" aria-atomic="true" align="center" class="alert alert-success">
            <h4>[nuxt-10] : asyncData et loading</h4>
              </div>
            <div>
              <div class="row">
                <div class="col-2">
                  <ul class="nav flex-column">
                    <li class="nav-item">
                      <a href="/nuxt-10/" target="_self" class="nav-link">
                        Home
                      </a>
                    </li>
                    <li class="nav-item">
                      <a href="/nuxt-10/page1" target="_self" class="nav-link active nuxt-link-active">
                        Page 1
                      </a>
                    </li>
                    <li class="nav-item">
                      <a href="/nuxt-10/page2" target="_self" class="nav-link">
                        Page 2
                      </a>
                    </li>
                  </ul>
                </div> <div class="col-10"><div role="alert" aria-live="polite" aria-atomic="true" class="alert alert-primary"> Page 1 -- result=3 </div></div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <script>window.__NUXT__ = (function (a, b, c) {
  return {
    layout: "default", data: [{ result: 3 }], error: null, serverRendered: true,
    logs: [
      { date: new Date(1574939615256), args: ["[page1 asyncData started]"], type: a, level: b, tag: c },
      { date: new Date(1574939620263), args: ["[page1 asyncData finished]"], type: a, level: b, tag: c },
      { date: new Date(1574939620285), args: ["[page1 beforeCreate]"], type: a, level: b, tag: c },
      { date: new Date(1574939620287), args: ["[page1 created]"], type: a, level: b, tag: c }
    ]
  }
    }("log", 2, ""));</script>
  <script src="/nuxt-10/_nuxt/runtime.js" defer></script>
  <script src="/nuxt-10/_nuxt/commons.app.js" defer></script>
  <script src="/nuxt-10/_nuxt/vendors.app.js" defer></script>
  <script src="/nuxt-10/_nuxt/app.js" defer></script>
</body>
</html>
  • Zeile 55: Man sieht, dass der Server dem Client ein Array [data] gesendet hat, das das Objekt [result:3] enthält, welches in das Objekt [data] der Seite [page1] des Servers eingebunden wurde. Damit der Client dasselbe tun und somit dieselbe Seite wie der Server anzeigen kann, übermittelt dieser ihm das Objekt [result]. Es sei daran erinnert, dass der Client die Funktion [asyncData] nicht ausführen wird. Er wird lediglich die vom Server berechneten Daten verwenden;

Navigieren wir nun mithilfe des Navigationsmenüs von der Seite [Home] zur Seite [Page 1]:

Image

  • Auf der Seite [1] erscheint der Fortschrittsbalken;

Nach 5 Sekunden wird die Seite [Page 1] angezeigt:

Image

Die Protokolle lauten wie folgt:

Image

Man sieht, dass der Client die Funktion [asyncData] vor dem Lebenszyklus der Seite ausgeführt hat.