【问题标题】:Vue.js - Wait for initial page render - then do calculationVue.js - 等待初始页面渲染 - 然后进行计算
【发布时间】:2019-08-05 05:35:25
【问题描述】:

在 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 方法会阻塞用户界面(如果显示加载组件就可以了),并且该组件仅在计算完成后更新。

有人知道我该如何规避这个问题吗? 提前非常感谢!

编辑: 在摆弄之后,我可以通过将setTimeout 设置为 1ms 来让它按照我想要的方式工作。这样,加载指示器显示出来,数据被正确处理,计算完成后加载指示器被成功移除。然而,这感觉就像一个非常肮脏的黑客,我很想避免它......

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

【问题讨论】:

    标签: vuejs2 vue-component nuxt.js


    【解决方案1】:

    对于上述情况,您需要使用 async/await,因为 javascript 是异步的,因此行不会一个接一个地执行。也就是说,如果您的函数被调用,引擎不会等待函数完成执行,而是并行执行下一行。

    因此,当您在函数上使用 async await 时,这些行将逐行执行。 你也可以使用 javascript promises。但是如果你从 store 中调用某个方法,那么你还需要在那里添加 async/await。

    您可以通过以下方式实现。

    async startCalculation() {
          if (store.data) {      
            // long running calculation, then
            await calculationFunction.then(() => {
              this.loading = false
              this.dataAvailable = true
            });
          }
        }
    

    【讨论】:

    • @Ridddhi,感谢您的评论!我想我需要指定:startCalculation 在这种情况下不是异步方法,因此不会返回承诺。在应用程序的其他地方,例如在从外部 API 加载数据的情况下,在异步等待数据的同时显示加载指示器非常简单。但是这个用例是不同的,因为方法是故意同步的。
    【解决方案2】:

    我的猜测可能是使用

    `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 Nuxt example

    编辑

    或者,您可以解除对代码的阻塞。 例如。找到第一个 vue-worker 库:

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

    Vue-Worker

    【讨论】:

    • 非常感谢您的回答!事实上,我尝试使用 nextTick,但在初始化计算之前加载组件仍然没有显示。在上面的答案中,我编辑了一个肮脏的黑客,目前导致正确的行为,但似乎真的很糟糕。
    • 这很奇怪,因为当堆栈被清空时调用 setTimeout 与在这种情况下重新渲染的 dom 相同。但通常尝试使用 webworker 在自己的“线程”中外包阻塞代码。然后它的非阻塞;)
    猜你喜欢
    • 2021-04-27
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多