Skip to content

13. Przykład [nuxt-10]: asyncData i ładowanie

Funkcja [asyncData] na stronie umożliwia asynchroniczne ładowanie danych, często pochodzących ze źródeł zewnętrznych. Funkcja [nuxt] czeka na zakończenie działania funkcji [asyncData] przed rozpoczęciem cyklu życia strony. Strona jest zatem renderowana dopiero po uzyskaniu danych zewnętrznych. Funkcja ta jest wykonywana zarówno przez serwer, jak i przez klienta zgodnie z następującymi zasadami:

  • gdy strona jest wywoływana bezpośrednio na serwerze, tylko serwer wykonuje funkcję [asyncData];
  • następnie podczas nawigacji po stronie klienta tylko klient wykonuje funkcję [asyncData];

Ostatecznie tylko jedna ze stron – klient lub serwer – wykonuje tę funkcję. Ponadto, gdy to klient wykonuje funkcję [asyncData], funkcja [nuxt] wyświetla pasek postępu, który można skonfigurować.

Funkcja [asyncData] umożliwia dostarczanie wyszukiwarkom stron wraz z ich danymi, co zwiększa ich znaczenie.

Przykład [nuxt-10] uzyskuje się początkowo poprzez skopiowanie projektu [nuxt-01]:

Image

Zmienia się jedynie strona [page1].

13.1. Strona [page1]

Kod strony [page1] jest następujący:


<!-- widok nr 1 -->
<template>
  <Layout :left="true" :right="true">
    <!-- nawigacja -->
    <Navigation slot="left" />
    <!-- komunikat-->
    <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',
  // używane komponenty
  components: {
    Layout,
    Navigation
  },
  // dane asynchroniczne
  asyncData(context) {
    // log
    console.log('[page1 asyncData started]')
    // zwracamy obietnicę
    return new Promise(function(resolve, reject) {
      // symulujemy funkcję asynchroniczną
      setTimeout(function () {
        // zwracamy wynik asynchroniczny – w tym przypadku liczbę losową
        resolve({ result: Math.floor(Math.random() * Math.floor(100)) })
        // log
        console.log('[page1 asyncData finished]')
      }, 5000)
    })
  },

  // cykl życia
  beforeCreate() {
    console.log('[page1 beforeCreate]')
  },
  created() {
    console.log('[page1 created]')
  },
  beforeMount() {
    console.log('[page1 beforeMount]')
  },
  mounted() {
    console.log('[page1 mounted]')
  }
}
</script>
  • wiersze 26–39: funkcja [asyncData]. Omówiliśmy już tę funkcję (zob. akapit z linkiem). Jest ona wykonywana przed cyklem życia strony. Z tego powodu nie można używać słowa kluczowego [this] w tej funkcji;
  • wiersz 30: funkcja musi zwracać obietnicę [Promise] lub wykorzystywać składnię async / await;
  • wiersze 32–37: asynchroniczna funkcja obietnicy jest symulowana z 5-sekundowym oczekiwaniem (wiersz 37);
  • wiersz 34: wynik funkcji asynchronicznej jest zwracany w postaci obiektu {result :...}. Obiekt asynchroniczny zwrócony przez funkcję [asyncData] jest włączany do obiektu [data] strony. Dlatego obiekt [result] jest dostępny w wierszu 7 szablonu, mimo że strona nie zdefiniowała obiektu [data];

13.2. Konfiguracja paska postępu obiektu [asyncData]

Gdy strona [page1] jest celem nawigacji w kliencie (tryb SPA), klient uruchamia funkcję [asyncData], a funkcja [nuxt] wyświetla wówczas pasek postępu, który ukrywa po zwróceniu wyniku przez funkcję [asyncData]. Właściwość [loading] pliku [nuxt.config.js] pozwala skonfigurować ten pasek:


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

Domyślnie obrazem oczekiwania funkcji [nuxt] jest pasek postępu o szerokości całej strony. Pasek ten ma określony kolor i grubość. Kolorowa kreska stopniowo powiększa się od 0% do 100% swojej wielkości, czyli mniej lub bardziej szybko w zależności od czasu oczekiwania.

  • wiersz 2: określa kolor paska postępu;
  • wiersz 3: określa grubość paska w pikselach;
  • wiersz 4: [throttle] to opóźnienie w milisekundach przed rozpoczęciem animacji. Dzięki temu nie pojawia się obraz animacji, gdy funkcja [asyncData] zwraca wynik szybko;
  • wiersz 5: [continuous] określa zachowanie animacji paska postępu. Domyślnie pasek powiększa się stopniowo od 0% do 100% swojego rozmiaru, mniej lub bardziej szybko w zależności od czasu oczekiwania. Dzięki funkcji [continuous:true] kolorowy pasek powiększa się ze stałą prędkością od 0 do 100% swojego rozmiaru, a następnie proces ten powtarza się, dopóki funkcja [asyncData] nie zwróci wyniku;

13.3. Exécution

Uruchommy aplikację, a następnie ręcznie wywołajmy na serwerze stronę [page1]:

Image

Oto logi:

Image

  • widać, że tylko serwer [1] wykonał funkcję [asyncData] i zrobił to przed cyklem strony;

Teraz przyjrzyjmy się stronie wysłanej przez serwer (kod źródłowy):


<!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>
  • wiersz 55: widać, że serwer wysłał do klienta tablicę [data], która zawiera obiekt [result:3], który został wbudowany w obiekt [data] strony [page1] serwera. Aby klient mógł postąpić analogicznie i wyświetlić tę samą stronę co serwer, serwer przekazuje mu obiekt [result]. Przypominamy, że klient nie wykona funkcji [asyncData]. Wykorzysta jedynie dane obliczone przez serwer;

Przejdźmy teraz ze strony [Home] do strony [Page 1], korzystając z menu nawigacyjnego:

Image

  • na stronie [1] pojawia się pasek postępu;

Po 5 sekundach wyświetla się strona [Page 1]:

Image

Logi są następujące:

Image

Widać, że klient wykonał funkcję [asyncData] przed rozpoczęciem cyklu życia strony.