13. Esempio [nuxt-10]: asyncData e caricamento
La funzione [asyncData] in una pagina consente il caricamento asincrono dei dati, che spesso sono esterni. [nuxt] attende che la funzione [asyncData] sia terminata prima di avviare il ciclo di vita della pagina. La pagina viene quindi renderizzata solo una volta ottenuti i dati esterni. Viene eseguita sia dal server che dal client secondo le seguenti regole:
- quando la pagina viene richiesta direttamente dal server, solo il server esegue la funzione [asyncData];
- poi, durante la navigazione lato client, solo il client esegue la funzione [asyncData];
In definitiva, solo uno dei due — client o server — esegue la funzione. Inoltre, quando il client esegue la funzione [asyncData], [nuxt] visualizza una barra di avanzamento che può essere configurata.
La funzione [asyncData] consente di fornire le pagine ai motori di ricerca insieme ai relativi dati, rendendole più significative.
L'esempio [nuxt-10] viene inizialmente creato clonando il progetto [nuxt-01]:

Cambia solo la pagina [page1].
13.1. La pagina [page1]
Il codice della pagina [page1] è il seguente:
<!-- vue n° 1 -->
<template>
<Layout :left="true" :right="true">
<!-- navigation -->
<Navigation slot="left" />
<!-- message-->
<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',
// components used
components: {
Layout,
Navigation
},
// asynchronous data
asyncData(context) {
// log
console.log('[page1 asyncData started]')
// we make a promise
return new Promise(function(resolve, reject) {
// we simulate an asynchronous function
setTimeout(function () {
// we make the result asynchronous - a random number here
resolve({ result: Math.floor(Math.random() * Math.floor(100)) })
// log
console.log('[page1 asyncData finished]')
}, 5000)
})
},
// life cycle
beforeCreate() {
console.log('[page1 beforeCreate]')
},
created() {
console.log('[page1 created]')
},
beforeMount() {
console.log('[page1 beforeMount]')
},
mounted() {
console.log('[page1 mounted]')
}
}
</script>
- righe 26–39: la funzione [asyncData]. Abbiamo già trattato questa funzione (vedi sezione collegata). Viene eseguita prima del ciclo di vita della pagina. Per questo motivo, la parola chiave [this] non può essere utilizzata all'interno della funzione;
- riga 30: deve restituire una [Promise] o utilizzare la sintassi async/await;
- righe 32–37: la funzione asincrona della promessa viene simulata con un'attesa di 5 secondi (riga 37);
- riga 34: il risultato della funzione asincrona viene restituito come oggetto {result:...}. L'oggetto asincrono restituito dalla funzione [asyncData] viene integrato nell'oggetto [data] della pagina. Questo è il motivo per cui l'oggetto [result] è disponibile alla riga 7 del template anche se la pagina non aveva definito un oggetto [data];
13.2. Configurazione della barra di avanzamento [asyncData]
Quando la pagina [page1] è la destinazione di una navigazione all'interno del client (modalità SPA), il client esegue la funzione [asyncData] e [nuxt] visualizza quindi una barra di avanzamento che nasconde una volta che la funzione [asyncData] ha restituito il suo risultato. La proprietà [loading] nel file [nuxt.config.js] consente di configurare questa barra:
loading: {
color: 'blue',
height: '5px',
throttle: 200,
continuous: true
},
Per impostazione predefinita, l'immagine di caricamento [nuxt] è una barra di avanzamento che si estende per tutta la larghezza della pagina. Questa barra ha un colore e uno spessore. La linea colorata cresce gradualmente dallo 0% al 100% della sua dimensione, a una velocità che varia a seconda della durata dell'attesa.
- riga 2: imposta il colore della barra di avanzamento;
- riga 3: imposta lo spessore della barra in pixel;
- riga 4: [throttle] è il ritardo in millisecondi prima che l'animazione inizi. Questo impedisce che un'immagine di animazione appaia quando la funzione [asyncData] restituisce rapidamente il suo risultato;
- riga 5: [continuous] imposta il comportamento dell'animazione della barra di avanzamento. Per impostazione predefinita, la barra cresce gradualmente dallo 0% al 100% della sua dimensione, a una velocità più o meno veloce a seconda del tempo di attesa. Con [continuous:true], la barra colorata cresce a velocità costante dallo 0 al 100% della sua dimensione, quindi si ripete fino a quando la funzione [asyncData] restituisce il suo risultato;
13.3. Esecuzione
Avviamo l'applicazione, quindi richiediamo manualmente la pagina [page1] dal server:

I log sono i seguenti:

- vediamo che solo il server [1] ha eseguito la funzione [asyncData], e lo ha fatto prima del ciclo della pagina;
Ora esaminiamo la pagina inviata dal server (codice sorgente):
<!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>
- Riga 55: Possiamo vedere che il server ha inviato al client un array [data] contenente l'oggetto [result:3], che è stato integrato nell'oggetto [data] della pagina [page1] del server. Affinché il client possa fare lo stesso e quindi visualizzare la stessa pagina del server, il server invia l'oggetto [result] al client. Ricordiamo che il client non eseguirà la funzione [asyncData]. Utilizzerà semplicemente i dati calcolati dal server;
Ora passiamo dalla pagina [Home] alla pagina [Page 1] utilizzando il menu di navigazione:

- In [1] compare la barra di avanzamento;
Dopo 5 secondi, viene visualizzata la pagina [Pagina 1]:

I log sono i seguenti:

Si può notare che il client ha eseguito la funzione [asyncData] prima dell'inizio del ciclo di vita della pagina.