Skip to content

13. Exemplo [nuxt-10]: asyncData e carregamento

A função [asyncData] numa página permite o carregamento assíncrono de dados, que são frequentemente externos. O [nuxt] aguarda que a função [asyncData] termine antes de iniciar o ciclo de vida da página. A página é, portanto, renderizada apenas depois de os dados externos terem sido obtidos. É executada tanto pelo servidor como pelo cliente de acordo com as seguintes regras:

  • quando a página é solicitada diretamente do servidor, apenas o servidor executa a função [asyncData];
  • depois, durante a navegação do lado do cliente, apenas o cliente executa a função [asyncData];

Em última análise, apenas um dos dois — cliente ou servidor — executa a função. Além disso, quando o cliente executa a função [asyncData], o [nuxt] exibe uma barra de progresso que pode ser configurada.

A função [asyncData] permite que as páginas sejam enviadas aos motores de busca juntamente com os seus dados, tornando-as mais significativas.

O exemplo [nuxt-10] é inicialmente criado através da clonagem do projeto [nuxt-01]:

Image

Apenas a página [page1] é alterada.

13.1. A página [page1]

O código da página [page1] é o seguinte:


<!-- 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>
  • linhas 26–39: a função [asyncData]. Já abordámos esta função (ver secção em link). É executada antes do ciclo de vida da página. Por este motivo, a palavra-chave [this] não pode ser utilizada dentro da função;
  • linha 30: deve devolver um [Promise] ou utilizar a sintaxe async/await;
  • linhas 32–37: a função assíncrona da promessa é simulada com uma espera de 5 segundos (linha 37);
  • linha 34: o resultado da função assíncrona é devolvido como um objeto {result:...}. O objeto assíncrono devolvido pela função [asyncData] é integrado no objeto [data] da página. É por isso que o objeto [result] está disponível na linha 7 do modelo, mesmo que a página não tenha definido um objeto [data];

13.2. Configurar a barra de progresso [asyncData]

Quando a página [page1] é o destino de uma navegação no cliente (modo SPA), o cliente executa a função [asyncData] e o [nuxt] exibe então uma barra de progresso que oculta assim que a função [asyncData] retorna o seu resultado. A propriedade [loading] no ficheiro [nuxt.config.js] permite configurar esta barra:


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

Por predefinição, a imagem de carregamento [nuxt] é uma barra de progresso que ocupa toda a largura da página. Esta barra tem uma cor e uma espessura. A linha colorida cresce gradualmente de 0% a 100% do seu tamanho, a um ritmo que varia consoante a duração da espera.

  • linha 2: define a cor da barra de progresso;
  • linha 3: define a espessura da barra em pixels;
  • linha 4: [throttle] é o atraso em milissegundos antes do início da animação. Isto evita que uma imagem de animação apareça quando a função [asyncData] devolve o seu resultado rapidamente;
  • linha 5: [continuous] define o comportamento da animação da barra de progresso. Por predefinição, a barra cresce gradualmente de 0% para 100% do seu tamanho, a um ritmo mais rápido ou mais lento, dependendo do tempo de espera. Com [continuous:true], a barra colorida cresce a uma velocidade constante de 0 a 100% do seu tamanho e, em seguida, repete-se até que a função [asyncData] devolva o seu resultado;

13.3. Execução

Vamos iniciar a aplicação e, em seguida, solicitar manualmente a página [page1] ao servidor:

Image

Os registos são os seguintes:

Image

  • vemos que apenas o servidor [1] executou a função [asyncData], e fê-lo antes do ciclo da página;

Agora, vamos examinar a página enviada pelo servidor (código-fonte):


<!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>
  • Linha 55: Podemos ver que o servidor enviou ao cliente um array [data] contendo o objeto [result:3], que foi integrado no objeto [data] da página [page1] do servidor. Para que o cliente possa fazer o mesmo e, assim, apresentar a mesma página que o servidor, o servidor envia o objeto [result] ao cliente. Lembre-se de que o cliente não executará a função [asyncData]. Ele utilizará simplesmente os dados calculados pelo servidor;

Agora, vamos navegar da página [Home] para a página [Page 1] utilizando o menu de navegação:

Image

  • Em [1], aparece a barra de progresso;

Após 5 segundos, temos a página [Página 1]:

Image

Os registos são os seguintes:

Image

Podemos ver que o cliente executou a função [asyncData] antes do ciclo de vida da página.