Skip to content

14. Exemplo [nuxt-11]: personalização da imagem de espera

Por predefinição, a imagem de espera da função [nuxt] é uma barra de progresso. O exemplo [nuxt-11] mostra que é possível substituí-la pela sua própria imagem de espera:

Image

O exemplo [nuxt-11] também mostra como gerir erros de carregamento.

Image

O exemplo [nuxt-11] é obtido inicialmente por cópia do exemplo [nuxt-10]:

Image

Vamos adicionar, no [1], um plugin para o cliente cuja função será gerir eventos entre componentes.

14.1. O plugin [event-bus]

O plugin [event-bus] será executado pelo cliente e pelo servidor, mas veremos que não funciona no lado do servidor. O seu código é o seguinte:


// cria-se um barramento de eventos entre as vistas
import Vue from 'vue'
export default (context, inject) => {
  // o barramento de eventos
  const eventBus = new Vue()
  // injeção de uma função [eventBus] no contexto
  inject('eventBus', () => eventBus)
}
  • linha 5: o barramento de eventos é uma instância da classe [Vue]. Com efeito, esta classe possui os métodos para gerir eventos:
    • [$emit]: para emitir um evento;
    • [$on]: para ficar à escuta de um evento específico;

Este barramento de eventos irá gerir apenas um evento, [loading], que será utilizado pelas páginas para iniciar/parar a animação de espera pelo fim de uma função assíncrona;

  • linha 7: cria-se uma função [$eventBus] (1.º argumento), cuja função será devolver o objeto [eventBus] que acabámos de criar (2.º argumento). Esta função é inserida no contexto para que esteja disponível nos objetos [context.app] e [this] das páginas;

14.2. O layout [default.vue]

O layout [default.vue] evolui da seguinte forma:


<template>
  <div class="container">
    <b-card>
      <!-- uma mensagem -->
      <b-alert show variant="success" align="center">
        <h4>[nuxt-11] : personnalisation de l'attente, gestion des erreurs</h4>
      </b-alert>
      <!-- a vista atual do encaminhamento -->
      <nuxt />
      <!-- a carregar -->
      <b-alert v-if="showLoading" show variant="light">
        <strong>Requête au serveur de données en cours...</strong>
        <div class="spinner-border ml-auto" role="status" aria-hidden="true"></div>
      </b-alert>
      <!-- erro de carregamento -->
      <b-alert v-if="showErrorLoading" show variant="danger">
        <strong>La requête au serveur de données a échoué : {{ errorLoadingMessage }}</strong>
      </b-alert>
    </b-card>
  </div>
</template>

<script>
/* eslint-disable no-console */
export default {
  name: 'App',
  data() {
    return {
      showLoading: false,
      showErrorLoading: false
    }
  },
  // ciclo de vida
  beforeCreate() {
    console.log('[default beforeCreate]')
  },
  created() {
    console.log('[default created]')
    // a escutar o evento [loading]
    this.$eventBus().$on('loading', this.mShowLoading)
    // bem como o evento [errorLoadingMessage]
    this.$eventBus().$on('errorLoading', this.mShowErrorLoading)
  },
  beforeMount() {
    console.log('[default beforeMount]')
  },
  mounted() {
    console.log('[default mounted]')
  },
  methods: {
    // gestão do carregamento
    mShowLoading(value) {
      console.log('[default mShowLoading], showLoading=', value)
      this.showLoading = value
    },
    // erro de carregamento
    mShowErrorLoading(value, errorLoadingMessage) {
      console.log('[default mShowErrorLoading], showErrorLoading=', value, 'errorLoadingMessage=', errorLoadingMessage)
      this.showErrorLoading = value
      this.errorLoadingMessage = errorLoadingMessage
    }
  }
}
</script>
  • linhas 11-14: a animação de espera. Só é apresentada se a propriedade [showLoading] for verdadeira (linha 29);
  • linhas 16-18: a mensagem de erro de carregamento. Só é apresentada se a propriedade [showErrorLoading] (linha 30) for verdadeira;
  • linhas 29-30: no carregamento inicial do componente, a animação de espera é ocultada, assim como a mensagem de erro;
  • linhas 37-43: quando é criada, a página escuta o evento [loading] (1.º argumento) no barramento de eventos criado pelo plugin. Ao recebê-lo, executa o método [mShowLoading] das linhas 52-55 (2.º argumento);
  • linhas 52-55: o valor recebido pelo método [mShowLoading] será um valor booleano (true/false). Serve para mostrar/ocultar a mensagem de espera;
  • linhas 41-42: quando é criada, a página escuta o evento [errorLoading] (1.º argumento) no barramento de eventos criado pelo plugin. Ao recebê-lo, executa o método [mShowErrorLoading] das linhas 57-61 (2.º argumento);
  • linha 57: o método [mShowErrorLoading] recebe dois argumentos:
    • o primeiro argumento é um valor booleano (true/false) para mostrar ou ocultar a mensagem de erro;
    • o segundo argumento só está presente se tiver ocorrido um erro. Representa a mensagem de erro a apresentar;
  • os registos das linhas 53 e 58 vão mostrar-nos que os métodos [showLoading] e [showErrorLoading] não são executados no lado do servidor;

14.3. A página [page1]

O código da página [page1] evolui da seguinte forma:


<!-- vista n.º 1 -->
<template>
  <Layout :left="true" :right="true">
    <!-- navegação -->
    <Navigation slot="left" />
    <!-- mensagem-->
    <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',
  // componentes utilizados
  components: {
    Layout,
    Navigation
  },
  // dados assíncronos
  asyncData(context) {
    // registo
    console.log('[page1 asyncData started]')
    // início da espera
    context.app.$eventBus().$emit('loading', true)
    // sem erros
    context.app.$eventBus().$emit('errorLoading', false)
    // retorna uma promessa
    return new Promise(function(resolve, reject) {
      // simulação de uma função assíncrona
      setTimeout(function() {
        // fim da espera
        context.app.$eventBus().$emit('loading', false)
        // registo
        console.log('[page1 asyncData finished]')
        // retornamos o resultado assíncrono — um número aleatório aqui
        resolve({ result: Math.floor(Math.random() * Math.floor(100)) })
      }, 5000)
    })
  },

  // ciclo de vida
  beforeCreate() {
    console.log('[page1 beforeCreate]')
  },
  created() {
    console.log('[page1 created]')
  },
  beforeMount() {
    console.log('[page1 beforeMount]')
  },
  mounted() {
    console.log('[page1 mounted]')
  }
}
</script>
  • as alterações ocorrem na função [asyncData], nas linhas 26-47;
  • linhas 29-30: antes do início da função assíncrona, é emitido o evento [loading] para as outras páginas da aplicação. Recorde-se que, na função [asyncData], ainda não se tem acesso ao objeto [this], que ainda não foi criado. Utiliza-se, então, o contexto que a função [asyncData] recebe como argumento (linha 26);
  • linha 30: utiliza-se o barramento de eventos para indicar que o carregamento está prestes a começar;
  • linha 38: utiliza-se o barramento de eventos para indicar que o carregamento está concluído;

Nota: Durante a execução, quando a página [page1] é solicitada ao servidor, a imagem de espera não é exibida. Nos registos, verifica-se que, do lado do servidor, o método [default.mShowLoading] não é chamado. De qualquer forma, ver a imagem de espera não faz sentido quando a página é solicitada ao servidor. Este só envia a página para o navegador do cliente depois de a função [asyncData] ter terminado. A imagem de espera torna-se, então, desnecessária. Este será o caso para todas as páginas da aplicação solicitadas diretamente ao servidor.

14.4. A página [index]

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


<!-- página principal -->
<template>
  <Layout :left="true" :right="true">
    <!-- navegação -->
    <Navigation slot="left" />
    <!-- mensagem-->
    <b-alert slot="right" show variant="warning">
      Home
    </b-alert>
  </Layout>
</template>

<script>
/* eslint-disable no-undef */
/* eslint-disable no-console */
/* eslint-disable nuxt/no-env-in-hooks */
/* eslint-disable nuxt/no-timing-in-fetch-data */

import Navigation from '@/components/navigation'
import Layout from '@/components/layout'

export default {
  name: 'Home',
  // componentes utilizados
  components: {
    Layout,
    Navigation
  },
  // dados assíncronos
  asyncData(context) {
    // registo
    console.log('[page1 asyncData started]')
    // início da espera
    context.app.$eventBus().$emit('loading', true)
    // sem erros
    context.app.$eventBus().$emit('errorLoading', false)
    // retorna uma promessa
    return new Promise(function(resolve, reject) {
      // simulação de uma função assíncrona
      setTimeout(function() {
        // fim da espera
        context.app.$eventBus().$emit('loading', false)
        // registo
        console.log('[page1 asyncData finished]')
        // retorna um erro
        reject(new Error("le serveur n'a pas répondu assez vite"))
      }, 5000)
    }).catch((e) => context.error({ statusCode: 500, message: e.message }))
  },
  // ciclo de vida
  beforeCreate() {
    console.log('[home beforeCreate]')
  },
  created() {
    console.log('[home created]')
  },
  beforeMount() {
    console.log('[home beforeMount]')
  },
  mounted() {
    console.log('[home mounted]')
    // sem erro
    this.$eventBus().$emit('errorLoading', false)
  }
}
</script>
  • linhas 30-49: a função [asyncData] é idêntica à da página [page1], com uma única diferença: na linha 46, a função assíncrona é encerrada em caso de falha (utilização do método [reject]);
  • linha 46: o parâmetro da função [reject] é uma instância da classe [Error]. O parâmetro do construtor [Error] é a mensagem de erro;
  • linha 48: este erro é interceptado pelo método [catch] da classe [Promise], que recebe o erro como parâmetro. Em seguida, utiliza-se a função [context.error] para declarar o erro. O parâmetro da função [context.error] é um objeto com, neste caso, duas propriedades:
    • [statusCode]: um código de erro HTTP;
    • [message]: uma mensagem de erro;

Quer a função [asyncData] seja executada pelo cliente ou pelo servidor, em caso de erro [context.error], a função [nuxt] apresenta a página [layouts / error.vue]:

Image

Embora se trate de uma página, a página [error.vue] é procurada na pasta [layouts] (talvez para evitar que seja incluída nas rotas da aplicação?). Aqui, a página [error.vue] é a seguinte:


<!-- definição HTML da vista -->
<template>
  <!-- formatação -->
  <Layout :left="true" :right="true">
    <!-- alerta na coluna da direita -->
    <template slot="right">
      <!-- mensagem sobre fundo amarelo -->
      <b-alert show variant="danger" align="center">
        <h4>L'erreur suivante s'est produite : {{ JSON.stringify(error) }}</h4>
      </b-alert>
    </template>
    <!-- menu de navegação na coluna da esquerda -->
    <Navigation slot="left" />
  </Layout>
</template>

<script>
/* eslint-disable no-undef */
/* eslint-disable no-console */
/* eslint-disable nuxt/no-env-in-hooks */

import Layout from '@/components/layout'
import Navigation from '@/components/navigation'

export default {
  name: 'Error',
  // componentes utilizados
  components: {
    Layout,
    Navigation
  },
  // propriedade [props]
  props: { error: { type: Object, default: () => 'waiting ...' } },
  // ciclo de vida
  beforeCreate() {
    // cliente e servidor
    console.log('[error beforeCreate]')
  },
  created() {
    // cliente e servidor
    console.log('[error created, error=]', this.error)
  },
  beforeMount() {
    // apenas cliente
    console.log('[error beforeMount]')
  },
  mounted() {
    // apenas cliente
    console.log('[error mounted]')
  }
}
</script>

Quando [nuxt] apresenta a página [error.vue], passa-lhe como propriedade [props], o erro que ocorreu (linha 33). Se o erro tiver sido causado por [context.error(objet1)], a propriedade [props] da página [error.vue] terá o valor [objet1]. A documentação [nuxt] indica que [objet1] deve ter, pelo menos, os atributos [statusCode, message]. A linha 9 apresenta a cadeia jSON do objeto [objet1] recebido.

14.5. A página [page2]

A página [page2] mostra outra forma de gerir o erro:

  • em [page1], o erro é apresentado numa página separada, [error.vue];
  • em [page2], o erro será apresentado na página [page2] que provocou o erro;

O código de [page2] é o seguinte:


<!-- vista n.º 2 -->
<template>
  <Layout :left="true" :right="true">
    <!-- navegação -->
    <Navigation slot="left" />
    <!-- mensagem -->
    <b-alert slot="right" show variant="secondary">
      Page 2
    </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',
  // componentes utilizados
  components: {
    Layout,
    Navigation
  },
  // dados assíncronos
  asyncData(context) {
    // registo
    console.log('[page2 asyncData started]')
    // início da espera
    context.app.$eventBus().$emit('loading', true)
    // sem erros
    context.app.$eventBus().$emit('errorLoading', false)
    // retorna uma promessa
    return new Promise(function(resolve, reject) {
      // simulação de uma função assíncrona
      setTimeout(function() {
        // fim da espera
        context.app.$eventBus().$emit('loading', false)
        // gera-se um erro arbitrário
        const errorLoadingMessage = "le serveur n'a pas répondu assez vite"
        // fim com sucesso
        resolve({ showErrorLoading: true, errorLoadingMessage })
        // registo
        console.log('[page2 asyncData finished]')
      }, 5000)
    })
  },
  // ciclo de vida
  beforeCreate() {
    console.log('[page2 beforeCreate]')
  },
  created() {
    console.log('[page2 created]')
  },
  beforeMount() {
    console.log('[page2 beforeMount]')
  },
  mounted() {
    console.log('[page2 mounted]')
    // cliente
    if (this.showErrorLoading) {
      console.log('[page2 mounted, showErrorLoading=true]')
      this.$eventBus().$emit('errorLoading', true, this.errorLoadingMessage)
    }
  }
}
</script>

Mais uma vez, insere-se uma função [asyncData] no código da página e, tal como [index], [page2] irá gerar um erro que, desta vez, iremos tratar de forma diferente.

  • linha 44: tanto o servidor como o cliente concluem a promessa com sucesso, devolvendo o resultado [{ showErrorLoading: true, errorLoadingMessage }]. Sabemos que isto terá como efeito incluir as propriedades [showerrorLoading, errorLoadingMessage] nas propriedades [data] da página e que o cliente irá receber essas propriedades;
  • linhas 60-67: sabe-se que a função [mounted] só é executada pelo cliente;
  • linha 63: o cliente verifica se a propriedade [showErrorLoading] foi definida (pelo servidor ou pelo cliente, conforme o caso). Se sim, emite o evento [‘errorLoading’] (linha 65) para que a página [default] exiba a mensagem de erro [this.errorLoadingMessage]. Por fim, o servidor envia uma página sem qualquer mensagem de erro visível. Esta é apresentada no último momento pelo cliente quando a página é «carregada»;

14.6. Exécution

14.6.1. [nuxt.config]

O ficheiro de execução [nuxt.config.js] é o seguinte:


export default {
  mode: 'universal',
  /*
   ** Headers of the page
   */
  head: {
    title: 'Introduction à [nuxt.js]',
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      {
        hid: 'description',
        name: 'description',
        content: 'ssr routing loading asyncdata middleware plugins store'
      }
    ],
    link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
  },
  /*
   ** Customize the progress-bar color
   */
  loading: false,

  /*
   ** Global CSS
   */
  css: [],
  /*
   ** Plugins to load before mounting the App
   */
  plugins: [{ src: '@/plugins/event-bus' }],
  /*
   ** Nuxt.js dev-modules
   */
  buildModules: [
    // Doc: https://github.com/nuxt-community/eslint-module
    '@nuxtjs/eslint-module'
  ],
  /*
   ** Nuxt.js modules
   */
  modules: [
    // Doc: https://bootstrap-vue.js.org
    'bootstrap-vue/nuxt',
    // Documentação: https://axios.nuxtjs.org/usage
    '@nuxtjs/axios'
  ],
  /*
   ** Axios module configuration
   ** See https://axios.nuxtjs.org/options
   */
  axios: {},
  /*
   ** Build configuration
   */
  build: {
    /*
     ** You can extend webpack config here
     */
    extend(config, ctx) {}
  },
  // diretório do código-fonte
  srcDir: 'nuxt-11',
  // router
  router: {
    // raiz da aplicação URL
    base: '/nuxt-11/'
  },
  // servidor
  server: {
    // porta de serviço, 3000 por predefinição
    port: 81,
    // endereços de rede em escuta, por predefinição localhost: 127.0.0.1
    // 0.0.0.0 = todos os endereços de rede do computador
    host: 'localhost'
  }
}
  • linha 22: define-se a propriedade [loading] como [false] para que [nuxt] não utilize a sua imagem de espera por predefinição;
  • linha 31: o plugin que define o barramento de eventos;

14.6.2. L, uma página [index] executada pelo servidor

Vamos solicitar a página [index] ao servidor (digitamos manualmente URL [http://localhost:81/nuxt-11/]). A página apresentada pelo navegador do cliente é a seguinte:

Image

Os registos são os seguintes:

Image

  • em [3], verifica-se que o servidor envia a página [error.vue];
  • em [4], verifica-se que o cliente também apresenta a página [error] com o mesmo erro que o servidor;
  • pode-se observar que o método [mShowLoading] da página [default] não foi chamado no lado do servidor, apesar de a página [index] ter ativado uma espera. Este método é chamado aquando da receção de um evento e, aparentemente, a gestão de eventos não está implementada no lado do servidor;

Vamos analisar o código-fonte da página recebida pelo navegador do cliente:


<!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-11/">
  <link rel="preload" href="/nuxt-11/_nuxt/runtime.js" as="script">
  <link rel="preload" href="/nuxt-11/_nuxt/commons.app.js" as="script">
  <link rel="preload" href="/nuxt-11/_nuxt/vendors.app.js" as="script">
  <link rel="preload" href="/nuxt-11/_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-11] : personnalisation de l'attente, gestion des erreurs</h4>
              </div>
            <div>
              <div class="row">
                <div class="col-2">
                  <ul class="nav flex-column">
                    <li class="nav-item">
                      <a href="/nuxt-11/" target="_self" class="nav-link active nuxt-link-active">
                        Home
                      </a>
                    </li>
                    <li class="nav-item">
                      <a href="/nuxt-11/page1" target="_self" class="nav-link">
                        Page 1
                      </a>
                    </li>
                    <li class="nav-item">
                      <a href="/nuxt-11/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" align="center" class="alert alert-danger">
                <h4>L'erreur suivante s'est produite : {&quot;statusCode&quot;:500,&quot;message&quot;:&quot;le serveur n'a pas répondu assez vite&quot;}</h4>
                    </div>
                </div>
              </div>
            </div>  
          </div>
        </div>
      </div>
    </div>
  </div>
  <script>window.__NUXT__ = (function (a, b, c, d) {
  d.statusCode = 500; d.message = "le serveur n'a pas répondu assez vite";
  return {
    layout: "default", data: [d], error: d, serverRendered: true,
    logs: [
      { date: new Date(1575047424168), args: ["[event-bus créé]"], type: a, level: b, tag: c },
      { date: new Date(1575047424175), args: ["[page1 asyncData started]"], type: a, level: b, tag: c },
      { date: new Date(1575047429455), args: ["[page1 asyncData finished]"], type: a, level: b, tag: c },
      { date: new Date(1575047429515), args: ["[default beforeCreate]"], type: a, level: b, tag: c },
      { date: new Date(1575047429675), args: ["[default created]"], type: a, level: b, tag: c },
      { date: new Date(1575047430157), args: ["[error beforeCreate]"], type: a, level: b, tag: c },
      { date: new Date(1575047430246), args: ["[error created, error=]", "{ statusCode: 500,\n  message: 'le serveur n\\'a pas répondu assez vite' }"], type: a, level: b, tag: c }]
  }
    }("log", 2, "", {}));</script>
  <script src="/nuxt-11/_nuxt/runtime.js" defer></script>
  <script src="/nuxt-11/_nuxt/commons.app.js" defer></script>
  <script src="/nuxt-11/_nuxt/vendors.app.js" defer></script>
  <script src="/nuxt-11/_nuxt/app.js" defer></script>
</body>
</html>
  • linha 57: verifica-se que o servidor enviou um objeto [d] que representa o erro que ocorreu no lado do servidor;
  • linha 59: observa-se uma propriedade [error] cujo valor é o objeto [d]. É possível imaginar que seja a presença da propriedade [error] na página enviada pelo servidor que faz com que os scripts do cliente apresentem a página [error.vue] com o erro [error];

14.6.3. A página [page1] executada pelo servidor

Digita-se manualmente URL [http://localhost:81/nuxt-11/page1]. Após 5 segundos, o navegador apresenta a seguinte página:

Image

Os registos apresentados são os seguintes:

Image

  • em [1], os registos do servidor. É possível observar que o método [mShowLoading] da página [default] não foi chamado;
  • em [2], os registos do cliente;

14.6.4. A página [page2] executada pelo servidor

Digitamos manualmente URL [http://localhost:81/nuxt-11/page2]. Após 5 segundos, o navegador apresenta a seguinte página:

Image

Analisemos os registos apresentados no navegador:

Image

  • em [1], os registos do servidor. Recorde-se que o servidor inseriu as propriedades [showErrorLoading, errorLoadingMessage] na página enviada ao navegador do cliente. Sabemos que, nessa altura, essas propriedades serão integradas nos [data] da página apresentada pelo cliente
  • em [3]; quando a página [page2] é carregada, encontra a propriedade [showErrorLoading] com o valor «verdadeiro». Envia então um evento para a página [default], para que esta exiba a mensagem de erro enviada pelo servidor [4];

14.6.5. A página [index] executada pelo cliente

Utilizam-se agora os links de navegação para apresentar as três páginas. Todas as páginas apresentadas pelo cliente são idênticas às apresentadas pelo servidor. A única diferença é que a imagem de espera ao fim dos 5 segundos é apresentada em todas as ocasiões.

Começamos pela página [index]. A imagem de espera é então apresentada:

Image

e, passados 5 segundos, obtém-se a página seguinte:

Image

A página final é, portanto, idêntica à obtida no lado do servidor.

Image

Recorde-se a função [asyncData] da página [index]:


asyncData(context) {
    // registo
    console.log('[page1 asyncData started]')
    // início da espera
    context.app.$eventBus().$emit('loading', true)
    // sem erros
    context.app.$eventBus().$emit('errorLoading', false)
    // retorna uma promessa
    return new Promise(function(resolve, reject) {
      // simulação de uma função assíncrona
      setTimeout(function() {
        // fim da espera
        context.app.$eventBus().$emit('loading', false)
        // registo
        console.log('[page1 asyncData finished]')
        // retorna um erro
        reject(new Error("le serveur n'a pas répondu assez vite"))
      }, 5000)
    }).catch((e) => context.error({ statusCode: 500, message: e.message }))
}

Os registos do cliente são os seguintes:

Image

  • na [1], a função [asyncData] é iniciada;
  • em [2], é iniciada a imagem de espera;
  • em [2-3], verifica-se que a página [default] recebeu os eventos [loading, true], [2] e [errorLoading, false] enviados pela função [asyncData] da página [index] (linhas 5 e 7);
  • em [4], fim da espera. A página [default] recebeu o evento [loading, false] enviado pela página [index] (linha 13);
  • em [5], a função [asyncData] concluiu o seu trabalho;
  • uma vez que a função [asyncData] gerou um erro com a [context.error] (linha 19), a página [error] é apresentada como [6];

14.6.6. A página [page1] executada pelo cliente

Após uma espera de 5 segundos, o cliente apresenta a página seguinte:

Image

Recorde-se o código da função [asyncData] a partir de [page1]:


asyncData(context) {
    // registo
    console.log('[page1 asyncData started]')
    // início da espera
    context.app.$eventBus().$emit('loading', true)
    // sem erro
    context.app.$eventBus().$emit('errorLoading', false)
    // retorna uma promessa
    return new Promise(function(resolve, reject) {
      // simula-se uma função assíncrona
      setTimeout(function() {
        // fim da espera
        context.app.$eventBus().$emit('loading', false)
        // registo
        console.log('[page1 asyncData finished]')
        // retornamos o resultado assíncrono — um número aleatório aqui
        resolve({ result: Math.floor(Math.random() * Math.floor(100)) })
      }, 5000)
    })
},

Os registos são os seguintes:

Image

14.6.7. A página [page2] executada pelo cliente

Após uma espera de 5 segundos, o cliente apresenta a seguinte página:

Image

Recorde-se o código das funções [asyncData] e [mounted] de [page2]:


asyncData(context) {
    // registo
    console.log('[page2 asyncData started]')
    // início da espera
    context.app.$eventBus().$emit('loading', true)
    // sem erros
    context.app.$eventBus().$emit('errorLoading', false)
    // retorna uma promessa
    return new Promise(function(resolve, reject) {
      // simula-se uma função assíncrona
      setTimeout(function() {
        // fim da espera
        context.app.$eventBus().$emit('loading', false)
        // gera-se um erro arbitrário
        const errorLoadingMessage = "le serveur n'a pas répondu assez vite"
        // fim com sucesso
        resolve({ showErrorLoading: true, errorLoadingMessage })
        // registo
        console.log('[page2 asyncData finished]')
      }, 5000)
    })
  }

mounted() {
    console.log('[page2 mounted]')
    // cliente
    if (this.showErrorLoading) {
      console.log('[page2 mounted, showErrorLoading=true]')
      this.$eventBus().$emit('errorLoading', true, this.errorLoadingMessage)
    }
}

Os registos são os seguintes:

Image

  • no [1], a página [default] recebeu o evento [showErrorLoading, true] enviado por [page2] (linha 29), que lhe solicita que apresente a mensagem de erro;