Vue.js - дождаться рендеринга начальной страницы - затем выполнить расчет - PullRequest
0 голосов
/ 14 марта 2019

В проекте Nuxt.js у меня есть страница, на которой мне нужно выполнить некоторые вычисления на стороне клиента, прежде чем некоторые данные будут отображены в таблице. До и во время расчета хочу показать экран загрузки.

Некоторый контекст: данные представляют собой графики, используемые фермером. Таблица должна показать, какой урожай был выращен на участке в последние годы. Данные хранятся в базе данных следующим образом:

plots = [{
  name: 'Plot1',
  year: 2017,
  crop: 'Wheat'
  ...
}, {
  name: 'Plot1',
  year: 2018,
  crop: 'Maize',
  ...
} ...]

В методе данные преобразуются во вложенный объект следующей структуры

data = {
  'Plot1': {
    2017: {
      'crop': 'Wheat',
      'catchCrop': true
    },
    2018: {
      'crop': 'Maize',
      'catchCrop': false
    }
  }
  ...
}

и впоследствии отображается в компоненте таблицы.

Макет компонента выглядит следующим образом:

<template>
  <loadingComponent v-if="loading"/>
  <tableComponent v-else-if="!loading && dataAvailable"/>
  <span v-else >No data</span>
</template>
<script>
  data() {
    return {
      loading: true,
      dataAvailable: false
    }
  },
  mounted() {
    this.startCalculation()
  },
  methods: {
    startCalculation() {
      if (store.data) {
        // long running calculation, then
        this.dataAvailable = true
      }
      this.loading = false
    }
  }
</script>

Проблема, с которой я сталкиваюсь, заключается в том, что компонент загрузки никогда не отображается. Однако метод startCalculation блокирует интерфейс пользователя (что было бы нормально, если бы отображался загружаемый компонент), и компонент обновляется только ПОСЛЕ завершения расчета.

Кто-нибудь имеет представление о том, как я мог бы обойти это? Большое спасибо заранее!

EDIT: Поиграв, я мог заставить его работать так, как я хочу, установив setTimeout в 1 мс. Таким образом, отображается индикатор загрузки, данные обрабатываются правильно, а затем индикатор загрузки удаляется после завершения расчета. Тем не менее, это похоже на очень грязный хак, и я хотел бы избежать этого ...

mounted() {
  this.loading = true
  // set short timeout in order for Vue to render the loading bar
  setTimeout(() => {
    this.startCalculation()
    this.loading = false
  },1)
}

Ответы [ 2 ]

1 голос
/ 14 марта 2019

Для вышеперечисленного вам необходимо использовать async / await, поскольку javascript является асинхронным и, следовательно, строки не выполняются одна за другой . То есть, если ваша функция вызывается, механизм не ждет, пока она завершит выполнение, но параллельно выполняет также следующие строки.

Следовательно, когда вы используете async await для своей функции, строки выполняются одна за другой. Вы также можете использовать javascript promises . Но если вы вызываете какой-то метод из хранилища, вам нужно будет также добавить туда async / await.

Вы можете достичь этого, как показано ниже.

async startCalculation() {
      if (store.data) {      
        // long running calculation, then
        await calculationFunction.then(() => {
          this.loading = false
          this.dataAvailable = true
        });
      }
    }
0 голосов
/ 15 марта 2019

Возможно, я бы использовал

`this.$nextTick().then(...DOM should be re-rendered ... do calculations)`

или в стиле async await для рендеринга loadingComponent перед блокировкой.

async function(){
    await this.$nextTick()
    // do calculations sync
    // await do calculations async
    // be happy
}

Vue.nextTick Пустой пример

Редактировать

Альтернативно можно просто разблокировать код.Например, с первым vue-worker lib найден поиск:

mounted(){
  this.loading = true;
  async ()=>{
    this.calculatedData= await this.$worker(doBlockingCalculation, ...args);
    this.loading = false;
  }
}

Vue-Worker

...