Skip to content

13. Приклад [nuxt-10]: asyncData та завантаження

Функція [asyncData] на сторінці дозволяє асинхронно завантажувати дані, які часто є зовнішніми. [nuxt] очікує завершення функції [asyncData] перед початком життєвого циклу сторінки. Отже, сторінка відображається лише після отримання зовнішніх даних. Вона виконується як сервером, так і клієнтом за такими правилами:

  • коли сторінка запитується безпосередньо на сервері, функцію [asyncData] виконує лише сервер;
  • потім під час навігації на стороні клієнта функцію [asyncData] виконує лише клієнт;

У підсумку функцію виконує лише один із двох — клієнт або сервер. Крім того, коли функцію [asyncData] виконує клієнт, функція [nuxt] відображає смугу прогресу, параметри якої можна налаштувати.

Функція [asyncData] дозволяє надавати пошуковим системам сторінки разом з їхніми даними, що робить їх більш релевантними.

Приклад [nuxt-10] спочатку отримується шляхом копіювання проєкту [nuxt-01]:

Image

Змінюється лише сторінка [page1].

13.1. Сторінка [page1]

Код сторінки [page1] такий:


<!-- вигляд № 1 -->
<template>
  <Layout :left="true" :right="true">
    <!-- навігація -->
    <Navigation slot="left" />
    <!-- повідомлення-->
    <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: {
    Layout,
    Navigation
  },
  // асинхронні дані
  asyncData(context) {
    // журнал
    console.log('[page1 asyncData started]')
    // повертається обіцянка
    return new Promise(function(resolve, reject) {
      // імітуємо асинхронну функцію
      setTimeout(function () {
        // повертаємо асинхронний результат — у цьому випадку випадкове число
        resolve({ result: Math.floor(Math.random() * Math.floor(100)) })
        // log
        console.log('[page1 asyncData finished]')
      }, 5000)
    })
  },

  // життєвий цикл
  beforeCreate() {
    console.log('[page1 beforeCreate]')
  },
  created() {
    console.log('[page1 created]')
  },
  beforeMount() {
    console.log('[page1 beforeMount]')
  },
  mounted() {
    console.log('[page1 mounted]')
  }
}
</script>
  • рядки 26–39: функція [asyncData]. Ми вже розглядали цю функцію (див. параграф за посиланням). Вона виконується до початку життєвого циклу сторінки. З цієї причини у функції не можна використовувати ключове слово [this];
  • рядок 30: вона повинна повертати обіцянку [Promise] або використовувати синтаксис async / await;
  • рядки 32–37: асинхронна функція обіцянки імітується з затримкою в 5 секунд (рядок 37);
  • рядок 34: результат асинхронної функції повертається у вигляді об’єкта {result :...}. Асинхронний об’єкт, повернений функцією [asyncData], інтегрується в об’єкт [data] сторінки. Саме тому об’єкт [result] доступний у рядку 7 шаблону, хоча на сторінці не було визначено об’єкта [data];

13.2. Налаштування індикатора прогресу для [asyncData]

Коли сторінка [page1] є ціллю навігації в клієнті (режим SPA), клієнт виконує функцію [asyncData], після чого [nuxt] відображає смугу прогресу, яку приховує, коли функція [asyncData] повернула свій результат. Властивість [loading] файлу [nuxt.config.js] дозволяє налаштувати цю смугу:


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

За замовчуванням зображенням очікування для [nuxt] є смуга прогресу, що займає всю ширину сторінки. Ця смуга має колір і товщину. Кольорова смуга поступово збільшується від 0 % до 100 % свого розміру, тобто швидше або повільніше залежно від тривалості очікування.

  • рядок 2: встановлює колір смуги прогресу;
  • рядок 3: визначає товщину смуги в пікселях;
  • рядок 4: [throttle] — це затримка в мілісекундах до початку анімації. Це дозволяє уникнути відображення анімаційного зображення, коли функція [asyncData] швидко повертає результат;
  • рядок 5: [continuous] визначає поведінку анімації смуги прогресу. За замовчуванням смуга поступово збільшується від 0 % до 100 % свого розміру, більш-менш швидко залежно від тривалості очікування. За допомогою [continuous:true] кольорова смуга збільшується з постійною швидкістю від 0 до 100 % свого розміру, а потім починає процес заново, доки функція [asyncData] не поверне результат;

13.3. Exécution

Запустимо додаток, а потім вручну запросимо у сервера сторінку [page1]:

Image

Журнали мають такий вигляд:

Image

  • бачимо, що лише сервер [1] виконав функцію [asyncData], і зробив це до циклу сторінки;

Тепер розглянемо сторінку, надіслану сервером (вихідний код):


<!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>
  • рядок 55: бачимо, що сервер надіслав клієнту масив [data], який містить об’єкт [result:3], що був інтегрований в об’єкт [data] сторінки [page1] сервера. Щоб клієнт міг зробити те саме і, отже, відобразити ту саму сторінку, що й сервер, сервер передає йому об’єкт [result]. Нагадаємо, що клієнт не виконуватиме функцію [asyncData]. Він просто використовуватиме дані, обчислені сервером;

Тепер перейдемо зі сторінки [Home] на сторінку [Page 1] за допомогою меню навігації:

Image

  • на сторінці [1] з’являється смуга прогресу;

Через 5 секунд з’являється сторінка [Page 1]:

Image

Журнали мають такий вигляд:

Image

Видно, що клієнт виконав функцію [asyncData] до початку життєвого циклу сторінки.