5. Beispiel [nuxt-02]: Server- und Client-Seiten
In diesem Projekt demonstrieren wir:
- dass die vom Client erstellte Seite anders aussehen kann als die vom Server empfangene. Dies führt zu einem schnellen Seitenwechsel, den der Benutzer bemerkt, was sich nachteilig auf die Benutzerfreundlichkeit der App auswirkt. Es ist daher eine Option, die vermieden werden sollte;
- eine Lösung, mit der die clientseitige Seite dieselbe Seite wie die vom Server gesendete nachbildet;
Das Projekt [nuxt-02] wird zunächst durch Klonen des Projekts [nuxt-01] erstellt.

Dem Projekt wird ein Ordner [store] sowie zwei neue Seiten hinzugefügt. Wir kommen später darauf zurück.
5.1. Die Seite [index]
5.1.1. Der Seitencode
Der Code für die [index]-Seite sieht nun wie folgt aus:
<!-- page principale -->
<template>
<Layout :left="true" :right="true">
<!-- navigation -->
<Navigation slot="left" />
<!-- message-->
<b-alert slot="right" show variant="warning"> Home - value= {{ value }} </b-alert>
</Layout>
</template>
<script>
/* eslint-disable no-undef */
/* eslint-disable no-console */
/* eslint-disable nuxt/no-env-in-hooks */
import Navigation from '@/components/navigation'
import Layout from '@/components/layout'
export default {
name: 'Home',
// components used
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
// life cycle
beforeCreate() {
// client and server
console.log('[home beforeCreate]')
},
created() {
// client and server
console.log('[home created]')
// server only
if (process.server) {
this.value = 10
}
// client and server
console.log('value=', this.value)
},
beforeMount() {
// customer only
console.log('[home beforeMount]')
},
mounted() {
// customer only
console.log('[home mounted]')
}
}
</script>
Kommentare
- Zeile 7: Die Seite [index] zeigt den Wert ihrer Eigenschaft [value] an (Zeile 28);
- Zeilen 36–45: Es ist wichtig, sich hier vor Augen zu halten, dass die Funktion [created] sowohl auf dem Server als auch auf dem Client ausgeführt wird. Zeilen 40–42: Der Server setzt den Wert der Eigenschaft [value] auf 10. Der Client ändert diesen Wert jedoch nicht. Wir wollen lediglich wissen, ob dieser Wert vom Client beibehalten wird. Wir werden feststellen, dass dies nicht der Fall ist;
5.1.2. Ausführung
Wir ändern die Datei [/nuxt.config.js], um das Projekt [nuxt-02] auszuführen:
...
// source code directory
srcDir: 'nuxt-02',
// router
router: {
// application URL root
base: '/nuxt-02/'
},
// server
server: {
// service port, default 3000
port: 81,
// network addresses listened to, default localhost: 127.0.0.1
// 0.0.0.0 = all the machine's network addresses
host: 'localhost'
}
...
Wir führen Projekt [1] aus:

Die [index]-Seite wird dann angezeigt [2-3]. Sie zeigt für einige Augenblicke den Wert [10] an und anschließend den Wert [0]. Was ist passiert?
Schritt 1
Der Server läuft zuerst. Er führt den Code auf der [index]-Seite aus:
export default {
name: 'Home',
// components used
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
// life cycle
beforeCreate() {
// client and server
console.log('[home beforeCreate]')
},
created() {
// client and server
console.log('[home created]')
// server only
if (process.server) {
this.value = 10
}
// client and server
console.log('value=', this.value)
},
beforeMount() {
// customer only
console.log('[home beforeMount]')
},
mounted() {
// customer only
console.log('[home mounted]')
}
}
- Aufgrund von Zeile 23 erhält die Eigenschaft [value] in Zeile 10 den Wert 10;
Sie können dies überprüfen, indem Sie sich den Quellcode der vom Browser empfangenen Seite ansehen (über die Option „Quelltext anzeigen“ im Browser):
<!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-02/">
<link rel="preload" href="/nuxt-02/_nuxt/runtime.js" as="script">
<link rel="preload" href="/nuxt-02/_nuxt/commons.app.js" as="script">
<link rel="preload" href="/nuxt-02/_nuxt/vendors.app.js" as="script">
<link rel="preload" href="/nuxt-02/_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-02] : page serveur, page client</h4>
</div> <div>
<div class="row">
<div class="col-2">
<ul class="nav flex-column">
<li class="nav-item">
<a href="/nuxt-02/" target="_self" class="nav-link active nuxt-link-active">
Home
</a>
</li>
<li class="nav-item">
<a href="/nuxt-02/page1" target="_self" class="nav-link">
Page 1
</a>
</li>
<li class="nav-item">
<a href="/nuxt-02/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-warning">
Home - value= 10
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>window.__NUXT__ = ....;</script>
<script src="/nuxt-02/_nuxt/runtime.js" defer></script>
<script src="/nuxt-02/_nuxt/commons.app.js" defer></script>
<script src="/nuxt-02/_nuxt/vendors.app.js" defer></script>
<script src="/nuxt-02/_nuxt/app.js" defer></script>
</body>
</html>
- Zeile 46: Auf der empfangenen Seite hatte [value] den Wert 10;
Schritt 2
Wir wissen, dass nach dem Empfang der Seite die Skripte in den Zeilen 57–60 die Kontrolle übernehmen und das Verhalten der empfangenen Seite, einschließlich der angezeigten Informationen, wie hier gezeigt, verändern. Diese Skripte bilden den Client, der auch den Code der [index]-Seite ausführt – denselben Code wie der Server:
export default {
name: 'Home',
// components used
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
// life cycle
beforeCreate() {
// client and server
console.log('[home beforeCreate]')
},
created() {
// client and server
console.log('[home created]')
// server only
if (process.server) {
this.value = 10
}
// client and server
console.log('value=', this.value)
},
beforeMount() {
// customer only
console.log('[home beforeMount]')
},
mounted() {
// customer only
console.log('[home mounted]')
}
}
- Um zu verstehen, was hier geschieht, muss man wissen, dass der [nuxt]-Client die Zeilen 22–24 (process.server=false) nicht ausführt;
- In einer klassischen [Vue]-Anwendung bleibt die Eigenschaft [value] in Zeile 10 auf 0. Deshalb wird der angezeigte Wert [0], sobald der Client zur empfangenen Seite navigiert ist;
Der vom [nuxt]-Server für die Eigenschaft [value] generierte Wert war nutzlos.
5.2. Die Seite [page1]
5.2.1. Der [Vuex]-Store
Wir haben dem [nuxt-02]-Projekt einen [store]-Ordner hinzugefügt:

Durch das Vorhandensein dieses Ordners implementiert [nuxt] automatisch einen [Vuex]-Store. Die Datei [index.js] implementiert diesen Store. Hier lautet der Inhalt der Datei [index.js] wie folgt:
export const state = () => ({
counter: 0
})
export const mutations = {
increment(state, inc) {
state.counter += inc
}
}
[nuxt] implementiert einen [Vuex]-Store basierend auf dem Inhalt von [index.js]:
- Zeilen 1–3: Definition des [state] des Stores. Dieser Zustand wird von einer Funktion zurückgegeben. Hier hat der Zustand nur eine Eigenschaft, den Zähler in Zeile 2. Die exportierte Funktion muss [state] heißen;
- Zeilen 5–9: die möglichen Operationen auf dem State des Stores. Diese werden als [Mutationen] bezeichnet. Hier erhöht die Mutation [increment] die Eigenschaft [counter] um den Wert [inc]. Das exportierte Objekt muss den Namen [mutations] tragen;
Der von [nuxt] implementierte Vuex-[store] ist an verschiedenen Stellen verfügbar. In Views ist er über die Eigenschaft [this.$store] verfügbar.
5.2.2. Der Seitencode
Wie die Seite [index] zeigt auch die Seite [page1] einen Wert an: den Zähler aus dem Vuex-Store:
<!-- page 1 -->
<template>
<Layout :left="true" :right="true">
<!-- navigation -->
<Navigation slot="left" />
<!-- message-->
<b-alert slot="right" show variant="primary"> Page 1 - value = {{ value }} </b-alert>
</Layout>
</template>
<script>
/* eslint-disable no-console */
import Navigation from '@/components/navigation'
import Layout from '@/components/layout'
export default {
name: 'Page1',
// components used
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
// life cycle
beforeCreate() {
// client and server
console.log('[home beforeCreate]')
},
created() {
// client and server
console.log('[home created]')
// server only
if (process.server) {
this.$store.commit('increment', 25)
}
// client and server
this.value = this.$store.state.counter
console.log('value=', this.value)
},
beforeMount() {
// customer only
console.log('[home beforeMount]')
},
mounted() {
// customer only
console.log('[home mounted]')
}
}
</script>
Kommentare
- Zeilen 38–40: Der Server erhöht den Zähler um 25;
- Zeile 42: Sowohl der Server als auch der Client zeigen den Zählerstand an;
- Zeile 7: Der Zählerstand wird angezeigt;
Beim Lesen dieses Codes müssen zwei Dinge beachtet werden:
- Der ausgeführte Code ist für Server und Client identisch;
- das [this]-Objekt ist nicht dasselbe: Es gibt ein serverseitiges [this] und ein clientseitiges [this];
Wir möchten wissen, ob das [this.$store] des Servers mit dem [this.$store] des Clients identisch ist. Da der Server zuerst läuft (beim Start der Anwendung), läuft dies auf die Frage hinaus: Wird das vom Server initialisierte [store] an den Client übergeben?
5.2.3. Ausführung
Wir führen das Projekt [nuxt-02] aus und geben manuell [localhost:81/nuxt-02/page1] ein, um den Server zu starten. Wie bei der Seite [index] beim Start:
- führt der Server die Seite [page1.vue] aus;
- sendet die generierte Seite an den Browser. Die Seite wird angezeigt;
- die in die gesendete Seite eingebetteten clientseitigen Skripte übernehmen und führen die Seite [page1.vue] erneut aus;
- die angezeigte Seite wird dann geändert;
Das Endergebnis sieht wie folgt aus:

Diesmal ist der angezeigte Wert tatsächlich der vom Server festgelegte, und optisch „springt“ die Seite nicht aufgrund einer clientseitigen Änderung des vom Server angezeigten Werts. Was ist diesmal passiert?
Der Server hat die folgende Seite [page1] ausgeführt:
...
<script>
/* eslint-disable no-console */
import Navigation from '@/components/navigation'
import Layout from '@/components/layout'
export default {
name: 'Page1',
// components used
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
// life cycle
beforeCreate() {
// client and server
console.log('[page1 beforeCreate]')
},
created() {
// client and server
console.log('[page1 created]')
// server only
if (process.server) {
this.$store.commit('increment', 25)
}
// client and server
this.value = this.$store.state.counter
console.log('value=', this.value)
},
beforeMount() {
// customer only
console.log('[page1 beforeMount]')
},
mounted() {
// customer only
console.log('[page1 mounted]')
}
}
</script>
- Die Zeilen 30–32 wurden fehlerfrei ausgeführt. Das bedeutet, dass [this.$store] auch auf der Serverseite auf den [Vuex]-Store verweist. In Zeile 31 wurde der Zähler des Stores auf 25 gesetzt;
- woraufhin die Seite an den Client gesendet wurde;
Wenn wir uns die vom Client empfangene Seite ansehen, finden wir folgende Elemente:
<!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-02/">
<link rel="preload" href="/nuxt-02/_nuxt/runtime.js" as="script">
<link rel="preload" href="/nuxt-02/_nuxt/commons.app.js" as="script">
<link rel="preload" href="/nuxt-02/_nuxt/vendors.app.js" as="script">
<link rel="preload" href="/nuxt-02/_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-02] : page serveur, page client</h4>
</div>
<div>
<div class="row">
<div class="col-2">
<ul class="nav flex-column">
<li class="nav-item">
<a href="/nuxt-02/" target="_self" class="nav-link">
Home
</a>
</li>
<li class="nav-item">
<a href="/nuxt-02/page1" target="_self" class="nav-link active nuxt-link-active">
Page 1
</a>
</li>
<li class="nav-item">
<a href="/nuxt-02/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 - value = 25
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
window.__NUXT__ = (function (a, b, c) {
return {
layout: "default", data: [{}], error: null, state: { counter: 25 }, serverRendered: true,
logs: [
{ date: new Date(1574085336802), args: ["[home beforeCreate]"], type: a, level: b, tag: c },
{ date: new Date(1574085336839), args: ["[home created]"], type: a, level: b, tag: c },
{ date: new Date(1574085336869), args: ["value=", "25"], type: a, level: b, tag: c }
]
}
}("log", 2, ""));</script>
<script src="/nuxt-02/_nuxt/runtime.js" defer></script>
<script src="/nuxt-02/_nuxt/commons.app.js" defer></script>
<script src="/nuxt-02/_nuxt/vendors.app.js" defer></script>
<script src="/nuxt-02/_nuxt/app.js" defer></script>
</body>
</html>
- Zeile 47: der vom Server gesendete Wert;
- Zeile 60: Wir sehen, dass der Zustand des [Vuex]-Stores in die Seite eingebettet wurde. Dies ermöglicht es dem Client, der nach dem Empfang der Seite ausgeführt wird, einen neuen [Vuex]-Store mit 25 als Anfangswert des Zählers zu rekonstruieren;
Nach dem Empfang und der Anzeige der Seite vom Server übernimmt der Client und führt nacheinander die Seite [page1] aus:
...
<script>
/* eslint-disable no-console */
import Navigation from '@/components/navigation'
import Layout from '@/components/layout'
export default {
name: 'Page1',
// components used
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
// life cycle
beforeCreate() {
// client and server
console.log('[page1 beforeCreate]')
},
created() {
// client and server
console.log('[page1 created]')
// server only
if (process.server) {
this.$store.commit('increment', 25)
}
// client and server
this.value = this.$store.state.counter
console.log('value=', this.value)
},
beforeMount() {
// customer only
console.log('[page1 beforeMount]')
},
mounted() {
// customer only
console.log('[page1 mounted]')
}
}
</script>
- Zeile 34: Der Eigenschaft [value] aus Zeile 18 wird der Wert 25 aus dem Zähler zugewiesen;
Der [nuxt]-Store ermöglicht es dem Server somit, beim ersten Laden der Seite, wenn die Seite vom Server angefordert wird, Informationen an den Client zu übertragen. Beachten Sie, dass der Server nach dem Abruf dieser Seite nicht mehr beteiligt ist und die Anwendung wie eine klassische [vue]-Anwendung im Single-Page-Modus funktioniert.
5.3. Die Seite [page2]
Auf der Seite [page2] zeigen wir eine weitere Möglichkeit für:
- der Server berechnet Informationen in die Seite ein;
- der Client diese Informationen nicht verändert;
5.3.1. Der Seitencode
Der Code für die Seite [page2] ändert sich wie folgt:
<!-- page2 -->
<template>
<Layout :left="true" :right="true">
<!-- navigation -->
<Navigation slot="left" />
<!-- message -->
<b-alert slot="right" show variant="secondary"> Page 2 - value = {{ value }} </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',
// components used
components: {
Layout,
Navigation
},
asyncData(context) {
// who executes this code?
console.log('asyncData, client=', process.client, 'serveur=', process.server)
// only for the server
if (process.server) {
// we return a promise
return new Promise(function(resolve, reject) {
// this is normally an asynchronous function
// we simulate it with a one-second wait
setTimeout(() => {
// this result will be included in the properties of [data]
resolve({ value: 87 })
// log
console.log('asynData terminée')
}, 1000)
})
}
},
// life cycle
beforeCreate() {
// client and server
console.log('[page2 beforeCreate]')
},
created() {
// client and server
console.log('[page2 created]')
},
beforeMount() {
// customer only
console.log('[page2 beforeMount]')
},
mounted() {
// customer only
console.log('[page2 mounted]')
}
}
</script>
- Zeile 7: Die Seite zeigt den Wert einer Eigenschaft namens [value] an;
- die Eigenschaft [value] ist nicht Teil eines von der Funktion [data] zurückgegebenen Objekts. Hier existiert diese Funktion nicht. Die Eigenschaft [value] wird dynamisch durch Zeile 36 erstellt;
- Zeile 25: Die Funktion [asyncData] ist eine [nuxt]-Funktion. Wie der Name schon sagt, handelt es sich in der Regel um eine asynchrone Funktion. Ihre übliche Aufgabe besteht darin, externe Daten abzurufen. [nuxt] stellt sicher, dass die Seite erst dann an den Browser des Clients gesendet wird, wenn die Funktion [asyncData] ihre asynchronen Daten gerendert hat;
- Die Funktion [asyncData] erhält den [nuxt]-Kontext als Parameter. Dieses Objekt ist sehr umfangreich und bietet Zugriff auf zahlreiche Informationen über die [nuxt]-Anwendung. Wir werden dies in den folgenden Abschnitten näher betrachten;
- Zeile 31: Wir implementieren die [asyncData]-Funktion unter Verwendung eines [Promise] (siehe das Dokument |Einführung in ECMAScript 6 anhand von Beispielen|). Der Konstruktor dieser Klasse akzeptiert eine asynchrone Funktion als Parameter, die:
- den Erfolg signalisiert, indem sie Daten mit der Funktion [resolve] zurückgibt. Das von dieser Funktion zurückgegebene Objekt wird automatisch in die [data]-Eigenschaften der Seite aufgenommen;
- einen Fehler signalisiert, indem es mithilfe der Funktion [reject] einen Fehler zurückgibt;
- Zeile 34: Wir simulieren eine asynchrone Funktion mithilfe der Funktion [setTimeout]. Diese Funktion gibt nach einer Sekunde (Zeile 31) mithilfe der Funktion [resolve] das Objekt [{ value: 87 }] (Zeile 36) zurück, was signalisiert, dass das [Promise] erfolgreich war. Das von der asynchronen Funktion zurückgegebene Objekt wird automatisch in die [data]-Eigenschaften der Seite aufgenommen. Und genau diese Eigenschaft wird in Zeile 7 angezeigt;
- Zeile 27: Wir werden sehen, dass die Funktion [asyncData] vom Server, nicht jedoch vom Client ausgeführt wird;
- Zeile 29: Die Eigenschaft [value] wird vom Server initialisiert;
Hinweis: Das [this]-Objekt wird in der [asyncData]-Funktion nicht erkannt, da das Objekt, das die [vue]-Komponente kapselt, noch nicht erstellt wurde;
5.3.2. Ausführung
Wir starten das Projekt [nuxt-02] und geben manuell [localhost:81/nuxt-02/page2] ein, um den Server zu starten. Wie beim ersten Start der Seite [index]:
- führt der Server die Seite [page2.vue] aus;
- sendet die generierte Seite an den Browser. Die Seite wird angezeigt;
- Die in die gesendete Seite eingebetteten clientseitigen Skripte übernehmen und führen die Seite [page2.vue] erneut aus;
- die angezeigte Seite wird dann geändert;
Das Endergebnis sieht wie folgt aus:

Diesmal ist der angezeigte Wert tatsächlich der vom Server festgelegte, und optisch „springt“ die Seite nicht aufgrund einer clientseitigen Änderung des vom Server angezeigten Werts. Was ist diesmal passiert?
Der Server hat die folgende Seite [page2] ausgeführt:
<!-- page2 -->
<template>
<Layout :left="true" :right="true">
<!-- navigation -->
<Navigation slot="left" />
<!-- message -->
<b-alert slot="right" show variant="secondary"> Page 2 - value = {{ value }} </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',
// components used
components: {
Layout,
Navigation
},
asyncData(context) {
// who executes this code?
console.log('asyncData, client=', process.client, 'serveur=', process.server)
// only for the server
if (process.server) {
// we return a promise
return new Promise(function(resolve, reject) {
// this is normally an asynchronous function
// we simulate it with a one-second wait
setTimeout(() => {
// this result will be included in the properties of [data]
resolve({ value: 87 })
// log
console.log('asynData terminée')
}, 1000)
})
}
},
// life cycle
beforeCreate() {
// client and server
console.log('[page2 beforeCreate]')
},
created() {
// client and server
console.log('[page2 created]')
},
beforeMount() {
// customer only
console.log('[page2 beforeMount]')
},
mounted() {
// customer only
console.log('[page2 mounted]')
}
}
</script>
Zeile 36 legt den Wert fest, der in Zeile 7 angezeigt wird. Dies ist das, was der Browser des Clients erhalten hat. Genauer gesagt hat er die folgende Seite erhalten:
<!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-02/">
<link rel="preload" href="/nuxt-02/_nuxt/runtime.js" as="script">
<link rel="preload" href="/nuxt-02/_nuxt/commons.app.js" as="script">
<link rel="preload" href="/nuxt-02/_nuxt/vendors.app.js" as="script">
<link rel="preload" href="/nuxt-02/_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-02] : page serveur, page client</h4>
</div>
<div>
<div class="row">
<div class="col-2">
<ul class="nav flex-column">
<li class="nav-item">
<a href="/nuxt-02/" target="_self" class="nav-link">
Home
</a>
</li>
<li class="nav-item">
<a href="/nuxt-02/page1" target="_self" class="nav-link">
Page 1
</a>
</li>
<li class="nav-item">
<a href="/nuxt-02/page2" target="_self" class="nav-link active nuxt-link-active">
Page 2
</a>
</li>
</ul>
</div>
<div class="col-10">
<div role="alert" aria-live="polite" aria-atomic="true" class="alert alert-secondary">
Page 2 - value = 87
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
window.__NUXT__ = (function (a, b, c) {
return {
layout: "default", data: [{ value: 87 }], error: null, state: { counter: 0 }, serverRendered: true,
logs: [
{ date: new Date(1574096608555), args: ["asyncData, client=", "false", "serveur=", "true"], type: a, level: b, tag: c },
{ date: new Date(1574096608575), args: ["[page2 beforeCreate]"], type: a, level: b, tag: c },
{ date: new Date(1574096608599), args: ["[page2 created]"], type: a, level: b, tag: c }
]
}
}("log", 2, ""));</script>
<script src="/nuxt-02/_nuxt/runtime.js" defer></script>
<script src="/nuxt-02/_nuxt/commons.app.js" defer></script>
<script src="/nuxt-02/_nuxt/vendors.app.js" defer></script>
<script src="/nuxt-02/_nuxt/app.js" defer></script>
</body>
</html>
- Zeile 48: Wir sehen, dass der Wert in der empfangenen Seite 87 ist;
- Zeile 61: In der Serverantwort sehen wir zwei Objekte: [data] und [state]:
- [state] ist der Zustand des [Vuex]-Speichers. Dieser wurde aus dem Inhalt des Ordners [store] in der Anwendung [nuxt-02] instanziiert;
- [data] enthält die vom Server mithilfe der Funktion [asyncData] erstellten Eigenschaften. Wir finden die vom Server erstellte Eigenschaft [value: 87]. Die clientseitigen Skripte werden diese Eigenschaft in die der Seite [page2] integrieren;
Kehren wir zum Code für die Seite [page2] zurück:
<!-- page2 -->
<template>
<Layout :left="true" :right="true">
<!-- navigation -->
<Navigation slot="left" />
<!-- message -->
<b-alert slot="right" show variant="secondary"> Page 2 - value = {{ value }} </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',
// components used
components: {
Layout,
Navigation
},
asyncData(context) {
// who executes this code?
console.log('asyncData, client=', process.client, 'serveur=', process.server)
// only for the server
if (process.server) {
// we return a promise
return new Promise(function(resolve, reject) {
// this is normally an asynchronous function
// we simulate it with a one-second wait
setTimeout(() => {
// this result will be included in the properties of [data]
resolve({ value: 87 })
// log
console.log('asynData terminée')
}, 1000)
})
}
},
// life cycle
beforeCreate() {
// client and server
console.log('[page2 beforeCreate]')
},
created() {
// client and server
console.log('[page2 created]')
},
beforeMount() {
// customer only
console.log('[page2 beforeMount]')
},
mounted() {
// customer only
console.log('[page2 mounted]')
}
}
</script>
- In Zeile 7 wird die Eigenschaft [value] verwendet. Die Seite definiert jedoch keine Eigenschaft mit dem Namen [value]. Die clientseitigen Skripte haben diese Eigenschaft automatisch anhand des vom Server empfangenen Objekts [data: [{ value: 87 }]] erstellt;
Die Protokolle zeigen außerdem, dass die Funktion [asyncData] vom Client nicht ausgeführt wurde:

Die Funktion [asyncData] wurde vom Server [1] ausgeführt, nicht jedoch vom Client [2]. Darüber hinaus ist zu beachten, dass Lebenszyklusfunktionen vom Server erst ausgeführt werden, wenn die Funktion [asyncData] beendet ist. Wir können die Wartezeit innerhalb der Funktion [asyncData] verlängern, um dies zu überprüfen.
5.4. Die Seite [page3]
Wir fügen unserer Anwendung eine neue Seite [page3] hinzu:

5.4.1. Die [Navigation]-Komponente
Die [navigation]-Komponente wird so angepasst, dass die Navigation zur neuen Seite möglich ist:
<template>
<!-- bootstrap menu with three options -->
<b-nav vertical>
<b-nav-item to="/" exact exact-active-class="active">
Home
</b-nav-item>
<b-nav-item to="/page1" exact exact-active-class="active">
Page 1
</b-nav-item>
<b-nav-item to="/page2" exact exact-active-class="active">
Page 2
</b-nav-item>
<b-nav-item to="/page3" exact exact-active-class="active">
Page 3
</b-nav-item>
</b-nav>
</template>
5.4.2. Der Code für [Seite 3]
Der Code für Seite [page3] lautet wie folgt:
<!-- page3 -->
<template>
<Layout :left="true" :right="true">
<!-- navigation -->
<Navigation slot="left" />
<!-- message -->
<b-alert slot="right" show variant="secondary"> Page 3 - value = {{ value }} </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: 'Page3',
// components used
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
fetch(context) {
// who executes this code?
console.log('fetch, client=', process.client, 'serveur=', process.server)
// only for the server
if (process.server) {
// we return a promise
return new Promise(function(resolve, reject) {
// this is normally an asynchronous function
// we simulate it with a one-second wait
setTimeout(() => {
// success
resolve()
}, 1000)
}).then(() => {
// modify the blind
context.store.commit('increment', 28)
})
}
},
// life cycle
beforeCreate() {
// client and server
console.log('[page3 beforeCreate]')
},
created() {
// client and server
this.value = this.$store.state.counter
console.log('[page3 created], value=', this.value)
},
beforeMount() {
// customer only
console.log('[page3 beforeMount]')
},
mounted() {
// customer only
console.log('[page3 mounted]')
}
}
</script>
- Zeile 30: Die Funktion [fetch] verhält sich ähnlich wie die Funktion [asyncData]:
- sie wird vor den Lebenszyklusfunktionen ausgeführt;
- das [this]-Objekt wird in dieser Funktion nicht erkannt;
- sie arbeitet asynchron;
- der Lebenszyklus beginnt erst, wenn die asynchrone Funktion ihr Ergebnis zurückgegeben hat;
- das Ergebnis wird hier durch die [then]-Methode des [Promise] in Zeile 43 zurückgegeben;
- Die [fetch]-Funktion erhält den Parameter [context]. Dieser repräsentiert den aktuellen [nuxt]-Kontext;
- Zeile 30: Unter seinen vielen Eigenschaften verfügt das [context]-Objekt über eine [store]-Eigenschaft, die den [Vuex]-Store der Anwendung repräsentiert;
- Zeile 41: Künstlich signalisieren wir den Erfolg des [Promise] nach einer Sekunde (siehe Dokument |Einführung in ECMAScript 6 anhand von Beispielen|);
- Zeile 45: Die [then]-Methode wird dann ausgeführt. Hier wird der [store]-Zähler erhöht;
5.4.3. Ausführung
Wir führen das [nuxt-02]-Projekt aus und geben manuell [localhost:81/nuxt-02/page3] ein, um den Server zu starten. Wie bei der [index]-Seite beim Start:
- führt der Server die Seite [page3.vue] aus;
- sendet die generierte Seite an den Browser. Die Seite wird angezeigt;
- Die in die gesendete Seite eingebetteten clientseitigen Skripte übernehmen und führen die Seite [page3.vue] erneut aus;
- die angezeigte Seite wird dann geändert;
Das Endergebnis sieht wie folgt aus:

Der angezeigte Wert ist tatsächlich der vom Server festgelegte, und optisch „springt“ die Seite nicht aufgrund einer clientseitigen Änderung des vom Server angezeigten Werts. Was ist diesmal passiert?
Der Server hat die folgende Seite [page3] ausgeführt:
<!-- page3 -->
<template>
<Layout :left="true" :right="true">
<!-- navigation -->
<Navigation slot="left" />
<!-- message -->
<b-alert slot="right" show variant="secondary"> Page 3 - value = {{ value }} </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: 'Page3',
// components used
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
fetch(context) {
// who executes this code?
console.log('fetch, client=', process.client, 'serveur=', process.server)
// only for the server
if (process.server) {
// we return a promise
return new Promise(function(resolve, reject) {
// this is normally an asynchronous function
// we simulate it with a one-second wait
setTimeout(() => {
// success
resolve()
}, 1000)
}).then(() => {
// modify the blind
context.store.commit('increment', 28)
// log
console.log('fetch commit terminé')
})
}
},
// life cycle
beforeCreate() {
// client and server
console.log('[page3 beforeCreate]')
},
created() {
// client and server
this.value = this.$store.state.counter
console.log('[page3 created], value=', this.value)
},
beforeMount() {
// customer only
console.log('[page3 beforeMount]')
},
mounted() {
// customer only
console.log('[page3 mounted]')
}
}
</script>
- Zeile 45: Die asynchrone Funktion [fetch] wird als erste der oben genannten Funktionen ausgeführt. Sie erhält als Parameter ein Objekt namens [context], das den aktuellen [Nuxt]-Kontext darstellt. Unter den vielen Eigenschaften dieses Objekts repräsentiert die Eigenschaft [context.store] den [Vuex]-Store;
- Zeile 45: In der asynchronen Funktion [fetch] setzt der Server den Zähler des Stores auf 28;
- Zeile 56: Wenn die Funktion [created] ausgeführt wird, stellt [nuxt] sicher, dass die asynchrone Funktion [fetch] ihre Arbeit beendet hat;
- Zeile 58: Der Wert des Zählers des Stores wird der Eigenschaft [value] in Zeile 27 zugewiesen;
- Zeile 7: Zeigt den Wert von [value] an, d. h. den Zähler des Stores;
Der Client-Browser erhält die folgende Seite:
<!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-02/">
<link rel="preload" href="/nuxt-02/_nuxt/runtime.js" as="script">
<link rel="preload" href="/nuxt-02/_nuxt/commons.app.js" as="script">
<link rel="preload" href="/nuxt-02/_nuxt/vendors.app.js" as="script">
<link rel="preload" href="/nuxt-02/_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-02] : page serveur, page client</h4>
</div>
<div>
<div class="row">
<div class="col-2">
<ul class="nav flex-column">
<li class="nav-item">
<a href="/nuxt-02/" target="_self" class="nav-link">
Home
</a>
</li>
<li class="nav-item">
<a href="/nuxt-02/page1" target="_self" class="nav-link">
Page 1
</a>
</li>
<li class="nav-item">
<a href="/nuxt-02/page2" target="_self" class="nav-link">
Page 2
</a>
</li>
<li class="nav-item">
<a href="/nuxt-02/page3" target="_self" class="nav-link active nuxt-link-active">
Page 3
</a>
</li>
</ul>
</div> <div class="col-10">
<div role="alert" aria-live="polite" aria-atomic="true" class="alert alert-secondary">
Page 3 - value = 28
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
window.__NUXT__ = (function (a, b, c) {
return {
layout: "default", data: [{}], error: null, state: { counter: 28 }, serverRendered: true,
logs: [
{ date: new Date(1574169916025), args: ["fetch, client=", "false", "serveur=", "true"], type: a, level: b, tag: c },
{ date: new Date(1574169917038), args: ["fetch commit terminé"], type: a, level: b, tag: c },
{ date: new Date(1574169917137), args: ["[page3 beforeCreate]"], type: a, level: b, tag: c },
{ date: new Date(1574169917167), args: ["[page3 created], value=", "28"], type: a, level: b, tag: c }
]
}
}("log", 2, ""));</script>
<script src="/nuxt-02/_nuxt/runtime.js" defer></script>
<script src="/nuxt-02/_nuxt/commons.app.js" defer></script>
<script src="/nuxt-02/_nuxt/vendors.app.js" defer></script>
<script src="/nuxt-02/_nuxt/app.js" defer></script>
</body>
</html>
- Zeile 52: Wir sehen, dass der Wert auf der empfangenen Seite 28 ist;
- Zeile 65: In der Serverantwort sehen wir, dass der Server den Status des [Vuex]-Stores an den Client gesendet hat. Anhand dieser Informationen können die Client-Skripte einen [Vuex]-Store rekonstruieren;
Die Client-Skripte führen wiederum den Code für die Seite [page3] aus:
<!-- page3 -->
<template>
<Layout :left="true" :right="true">
<!-- navigation -->
<Navigation slot="left" />
<!-- message -->
<b-alert slot="right" show variant="secondary"> Page 3 - value = {{ value }} </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: 'Page3',
// components used
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
fetch(context) {
// who executes this code?
console.log('fetch, client=', process.client, 'serveur=', process.server)
// only for the server
if (process.server) {
// we return a promise
return new Promise(function(resolve, reject) {
// this is normally an asynchronous function
// we simulate it with a one-second wait
setTimeout(() => {
// success
resolve()
}, 1000)
}).then(() => {
// modify the blind
context.store.commit('increment', 28)
// log
console.log('fetch commit terminé')
})
}
},
// life cycle
beforeCreate() {
// client and server
console.log('[page3 beforeCreate]')
},
created() {
// client and server
this.value = this.$store.state.counter
console.log('[page3 created], value=', this.value)
},
beforeMount() {
// customer only
console.log('[page3 beforeMount]')
},
mounted() {
// customer only
console.log('[page3 mounted]')
}
}
</script>
- Zeile 58: Die vom Client ausgeführte Funktion [created] setzt den Zählerwert auf die Eigenschaft [value] in Zeile 27;
- Zeile 7 zeigt diesen Wert an. Da er mit dem vom Server gesendeten Wert übereinstimmt, sehen wir keinen „Sprung“ der Seite aufgrund einer Änderung;
Die Protokolle zeigen außerdem, dass die [fetch]-Funktion vom Client nicht ausgeführt wurde:

Die Funktion [fetch] wurde vom Server [1] ausgeführt, nicht jedoch vom Client [2]. Beachten Sie außerdem, dass die Lebenszyklusfunktionen vom Server erst ausgeführt werden, wenn die Funktion [fetch] beendet ist [3]. Wir können die Wartezeit innerhalb der Funktion [fetch] verlängern, um dies zu überprüfen.
Die Seiten [page1] und [page3] zeigten zwei Methoden, bei denen der [Vuex]-Store verwendet wurde, um Informationen vom Server an den Client zu übertragen. Man könnte sich fragen, ob diese gleichwertig sind. Wir werden eine Seite [page4] erstellen, um dies zu überprüfen.
5.5. Die Seite [page4]
Wir fügen unserer Anwendung eine neue Seite [page4] hinzu:

5.5.1. Die [navigation]-Komponente
Die [navigation]-Komponente wird so angepasst, dass die Navigation zur neuen Seite möglich ist:
<template>
<!-- bootstrap menu with five options -->
<b-nav vertical>
<b-nav-item to="/" exact exact-active-class="active">
Home
</b-nav-item>
<b-nav-item to="/page1" exact exact-active-class="active">
Page 1
</b-nav-item>
<b-nav-item to="/page2" exact exact-active-class="active">
Page 2
</b-nav-item>
<b-nav-item to="/page3" exact exact-active-class="active">
Page 3
</b-nav-item>
<b-nav-item to="/page4" exact exact-active-class="active">
Page 4
</b-nav-item>
</b-nav>
</template>
5.5.2. Der Code für [Seite4]
Der Code für Seite [page4] lautet wie folgt:
<!-- page4 -->
<template>
<Layout :left="true" :right="true">
<!-- navigation -->
<Navigation slot="left" />
<!-- message -->
<b-alert slot="right" show variant="secondary"> Page 4 - value = {{ value }} </b-alert>
</Layout>
</template>
<script>
/* eslint-disable no-console */
import Navigation from '@/components/navigation'
import Layout from '@/components/layout'
export default {
name: 'Page4',
// components used
components: {
Layout,
Navigation
},
data() {
return {
value: 0
}
},
// life cycle
async beforeCreate() {
// client and server
console.log('[page4 beforeCreate]')
// only for the server
if (process.server) {
// execute the asynchronous function
const valeur = await new Promise(function(resolve, reject) {
// this is normally an asynchronous function
// we simulate it with a 10-second wait
setTimeout(() => {
// success - the counter value is returned
resolve(52)
}, 10000)
})
// modify the blind
this.$store.commit('increment', valeur)
// log
console.log('[page4 beforeCreate], fonction asynchrone terminée, compteur=', this.$store.state.counter)
}
},
created() {
// client and server
this.value = this.$store.state.counter
console.log('[page4 created], value=', this.value)
},
beforeMount() {
// customer only
console.log('[page4 beforeMount]')
},
mounted() {
// customer only
console.log('[page4 mounted]')
}
}
</script>
- Zeile 30: Was zuvor in der Funktion [fetch] erfolgte, wird nun in der Methode [beforeCreate] ausgeführt. Wir verwenden das Paar async (Zeile 30) / await (Zeile 36), um auf den Abschluss der asynchronen Funktion zu warten;
- Zeile 36: Wir rufen das Ergebnis der asynchronen Funktion, das in Zeile 41 zurückgegeben wurde, nach 10 Sekunden ab (Zeile 42);
- Zeilen 50–54: In der Methode [created], die sowohl auf dem Server als auch auf dem Client ausgeführt wird, wird der Zähler der Eigenschaft [value] der Seite zugewiesen;
5.5.3. Ausführung
Führen Sie das Projekt [nuxt-02] aus und geben Sie manuell [localhost:81/nuxt-02/page4] ein, um den Server zu starten. Wie beim ersten Start der Seite [index]:
- führt der Server die Seite [page4.vue] aus;
- sendet die generierte Seite an den Browser. Die Seite wird angezeigt;
- Die in die gesendete Seite eingebetteten clientseitigen Skripte übernehmen und führen die Seite [page4.vue] erneut aus;
- die angezeigte Seite wird dann geändert;
Das Endergebnis sieht wie folgt aus:

Entgegen den Erwartungen ist der in [2] angezeigte Wert nicht 52. Was ist passiert?
Die Protokolle lauten wie folgt:

Wir sehen, dass in [1] das Protokoll, das das Ende der asynchronen Aktion anzeigt, nicht angezeigt wurde. Die Funktion [created], die den Zählerwert anzeigt, gibt 0 zurück. All dies deutet darauf hin, dass [nuxt] nicht auf den Abschluss der asynchronen Aktion gewartet hat.
Kehren wir zum VSCode-Terminal zurück, das zum Starten der Anwendung verwendet wurde, finden wir die Protokolle [3-4]. Wir können sehen, dass die asynchrone Funktion tatsächlich auf der Serverseite ausgeführt wurde.
Letztendlich wurde die Funktion [beforeCreate] tatsächlich vollständig auf der Serverseite ausgeführt, aber [Nuxt] hat nicht auf deren Beendigung gewartet, bevor die Seite an den Client-Browser gesendet wurde, obwohl es auf die Beendigung der Funktion [fetch] wartet. Daher ist dies die Methode, die Sie verwenden sollten, wenn Sie möchten, dass der Server einen [Vuex]-Store initialisiert.
5.6. Navigation in der [Vue]-Anwendung
Wir haben gezeigt, was passiert, wenn jede der Seiten [index, page1, page2, page3, page4] vom Server geladen wird. In der Praxis ist dies jedoch nicht der Fall: Im Normalbetrieb wird nur die Seite [index] vom Server abgerufen. Betrachten wir die drei Seiten in diesem Fall:
Seite [index]

Wir haben dieses Ergebnis bereits im Abschnitt „Link“ erläutert.
Klicken wir nun auf den Link [Seite 1]:

Der angezeigte Wert ist 0. Er betrug 25, als die Seite durch manuelle Eingabe der URL erstmals vom Server angefordert wurde. Die Erklärung ist einfach. Der ausgeführte Code lautet wie folgt:
created() {
// client and server
console.log('[page1 created]')
// server only
if (process.server) {
this.$store.commit('increment', 25)
}
// client and server
this.value = this.$store.state.counter
console.log('value=', this.value)
},
Zeile 6 war diejenige, die den Zähler auf 25 gesetzt hat. Da die Seite nicht vom Server angefordert wurde, wurden die Zeilen 5–7 nicht ausgeführt, und der Zähler im [Vuex]-Store blieb bei 0.
Klicken wir nun auf den Link [Seite 2]:

Diesmal wird kein Wert angezeigt, und wir sehen außerdem eine Warnung in den Konsolenprotokollen:

- In [1] sehen wir, dass die Funktion [asyncData] vom Client ausgeführt wurde. Dies ist immer der Fall:
- Sie wird vom Server ausgeführt, wenn die Seite vom Server angefordert wird. In diesem Fall wird sie nicht vom Client ausgeführt;
- jedes Mal, wenn die Seite das Ziel der aktuellen Route des Clients ist;
- in [2]: [nuxt] gibt eine Warnung aus, da die Seitenvorlage einen reaktiven Ausdruck {{ value }} enthält, obwohl die Seite keine [value]-Eigenschaft hat;
Sehen wir uns den vom Client ausgeführten Code noch einmal an:
asyncData() {
// who executes this code?
console.log('asyncData, client=', process.client, 'serveur=', process.server)
// only for the server
if (process.server) {
// we return a promise
return new Promise(function(resolve, reject) {
// this is normally an asynchronous function - so not here
// this result will be included in the properties of [data]
resolve({ value: 87 })
})
}
},
- Zeile 3 zeigte, dass die Funktion [asyncData] vom Client noch vor den Lebenszyklusfunktionen ausgeführt wurde;
- Zeile 5 verhinderte die Ausführung des restlichen Codes, der die Eigenschaft [value] erstellte, da dieser Code vom Client ausgeführt wird;
Kommen wir nun zur Seite [page3]:

- In [2] hatten wir den Wert 28, als die Seite vom Server bereitgestellt wurde. Das ist hier nicht der Fall;
- In [4] sehen wir, dass die Funktion [fetch] auf der Client-Seite ausgeführt wurde;
Schauen wir uns den vom Client ausgeführten Code an:
...
fetch(context) {
// who executes this code?
console.log('fetch, client=', process.client, 'serveur=', process.server)
// only for the server
if (process.server) {
// we return a promise
return new Promise(function(resolve, reject) {
// this is normally an asynchronous function
// we simulate it with a one-second wait
setTimeout(() => {
// success
resolve()
}, 1000)
}).then(() => {
// modify the blind
context.store.commit('increment', 28)
// log
console.log('fetch commit terminé')
})
}
},
...
- Der Client führt die [fetch]-Methode aus, Zeile 2;
- die Zeilen 6–21 werden nicht ausgeführt, da die Bedingung [process.server] falsch ist. Daher wird Zeile 17, die den Zähler auf 28 setzt, nicht ausgeführt. Er bleibt bei Null. Deshalb zeigt der Client 0 statt 28 an;
Gehen wir nun weiter zu Seite [page4]. Wir erhalten folgendes Ergebnis:

- in [2] den Wert des Zählers;
- in [3] die Client-Protokolle;
Der vom Client ausgeführte Code lautet wie folgt:
...
data() {
return {
value: 0
}
},
// life cycle
async beforeCreate() {
// client and server
console.log('[page4 beforeCreate]')
// only for the server
if (process.server) {
// execute the asynchronous function
const valeur = await new Promise(function(resolve, reject) {
// this is normally an asynchronous function
// we simulate it with a 10-second wait
setTimeout(() => {
// success - the counter value is returned
resolve(52)
}, 10000)
})
// modify the blind
this.$store.commit('increment', valeur)
// log
console.log('[page4 beforeCreate], fonction asynchrone terminée, compteur=', this.$store.state.counter)
}
},
created() {
// client and server
this.value = this.$store.state.counter
console.log('[page4 created], value=', this.value)
},
...
- Die Zeilen 12–26 werden vom Client nicht ausgeführt, da die Bedingung [process.server] in Zeile 12 falsch ist. Daher ist der Zähler im [Vuex]-Store 0 (sein Anfangswert im Store), und dies ist der Wert, der auf der Seite angezeigt wird;
Vielleicht fragen Sie sich, was passiert, wenn Sie die [if]-Anweisungen in den Zeilen 12 und 26 auskommentieren. Hier ist die Antwort:
- Diesmal führt der Client die Zeilen 14–25 aus, aber [nuxt] wartet nicht darauf, dass die asynchrone Funktion beendet wird (wie es auf dem Server der Fall ist), und lässt den Zähler daher auf 0 stehen;
- Nach 10 Sekunden ist die asynchrone Funktion abgeschlossen und der Zähler wird in Zeile 23 auf 52 gesetzt;
- Wenn man zurück zur Seite [page4] navigiert, wird dann der Wert 52 angezeigt;
5.7. Zusammenfassung
Aus unseren verschiedenen Tests können wir Folgendes schließen:
- Wenn die Seite [index] externe Daten enthalten muss, können diese Daten vom Server mithilfe der Funktion [asyncData] abgerufen werden;
- Wenn der Server beim Laden der Seite [index] einen [Vuex]-Store mit externen Daten initialisieren muss, erfolgt dies in der Funktion [fetch];
- Die vom Server generierte Seite und die vom Client generierte Seite müssen identisch sein, um den „Jittering“-Effekt zu vermeiden, der dadurch entsteht, dass die vom Server gesendete und zunächst angezeigte Seite visuell durch die clientseitige Seite ersetzt wird;
Wir werden weitere Aspekte von [Nuxt] anhand eines neuen Beispiels untersuchen.