Running asynchronous setTimeout counter parallely to Promise.all() to display a progress loader in %

Hey guys,

i hope you are all good!

I am having an issue to run an asynchronous setTimeout counter parallely to a Promise.all() handler when trying to display a progress loader in %.

Here the details:

I ve built a Vue app consisting of three components.

The first component “Test.vue” is importing a progress bar component and a pivot component which is containing about 12 pivot tables with data from different Google firestore collections (handled via Promise.all()).
Currently it takes about 15 seconds until the pivot component is rendered successfully.
During this waiting period i want to show a progress bar in % which goes up to 100% until all data for the pivot component is loaded and rendered successfully.

I was trying different approaches and currently I am following the “easy” approach that the progress bar just shall display within 15 seconds the loading progress.

But even this approach doesn’t work properly for me.

It seems to me like the progress functionality always waits until the loading and rendering of the pivot component is finished.

I really don’t have any idea anymore how to solve this.

Which recommendations do you have?

Thank you and best regards!

Hint (if important): Inside the pivot component the data is loaded inside the mounted-hook via Promise.all()

Here the code for the Test.vue component:

Test.vue: 

<template>
  <mdb-container class="full-width" style="margin-top:35px !important;">
    <mdb-row v-if="tabChange">
      <mdb-progress :height="30" :value="value">{{value}} %</mdb-progress>
    </mdb-row>
    <mdb-card>
      <mdb-card-header>
        <mdb-tab default class="card-header-tabs">
          <mdb-tab-item 
            v-for="tab in tabs"
            v-bind:key="tab"
            v-bind:class="[{ active: currentTab === tab }]"
            :active="currentTab == tab"
            @click.native.prevent="currentTab=tab"
            >{{ tab }}</mdb-tab-item>
        </mdb-tab>
      </mdb-card-header>
        <mdb-card-body>
          <mdb-tab-content>
            <mdb-tab-pane class="fade">
              <mdb-row>
                <keep-alive>
                  <component v-bind:is="currentTabComponent" v-on:finished="setFinished" class="tab"></component>
                </keep-alive>
              </mdb-row>
            </mdb-tab-pane>
          </mdb-tab-content>
        </mdb-card-body>
    </mdb-card>
  </mdb-container>
</template>

<script>


/* eslint-disable */
import { mdbProgress, mdbContainer,  mdbRow, mdbCol, mdbBtn, mdbCard, mdbCardTitle, mdbCardText, mdbCardFooter, mdbCardBody, mdbCardHeader, mdbListGroup, mdbListGroupItem, mdbNavItem, mdbCardGroup, mdbIcon, mdbFooter, mdbTab, mdbTabItem, mdbTabContent, mdbTabPane } from 'mdbvue';

import { db } from '@/main'
import PivotTable from '@/components/flight-builder/PivotTable'
import DefaultFilters from '@/components/flight-builder/filters/DefaultFilters'
import MainTab from '@/components/flight-builder/ads-archive/MainTab'
import Channel from '@/components/flight-builder/ads-archive/Channel'
import Loader from '@/components/Loader'
//import excel from "vue-excel-export"

/*const Channel = () => ({
  component: import('@/components/flight-builder/ads-archive/Channel'),
  loading: LoadingComponent,
  error: LoadingComponent,
  delay: 200,
  timeout: 3000
})*/

export default {
  name: 'AdsArchivePage',
  components: {
    PivotTable,
    mdbContainer,
    mdbRow,
    mdbCol,
    mdbBtn,
    mdbCard,
    mdbCardTitle,
    mdbCardText,
    mdbCardFooter,
    mdbCardBody,
    mdbCardHeader,
    mdbListGroup,
    mdbListGroupItem,
    mdbNavItem,
    mdbCardGroup,
    mdbIcon,
    mdbFooter,
    mdbTab,
    mdbTabItem,
    mdbTabContent,
    mdbTabPane,
    mdbProgress,
    DefaultFilters,
    MainTab,
    Channel,
    Loader
  },
  data: () => {
    return {
      active: 0,
      currentTab: "Main Tab",
      value: 0,
      tabs: ["Main Tab", "Channel", "Flight", "AdType", "Creative", "Spot length"],
      componentMatcher: {
        "Main Tab": "",
        "Channel": Channel,
        "Flight": "",
        "AdType": "",
        "Creative": "",
        "Spot length": ""
      },
      finishedLoading: false
    }
 
  },
  methods: {
    setFinished(finishedLoading) {
      this.finishedLoading = finishedLoading
    },
    timeout(ms) { //pass a time in milliseconds to this function
        return new Promise(resolve => setTimeout(resolve, ms));
    },
    async wait() {
      let loadingTime = 15
      this.value = 0
      console.log("wait123")
      for (let i = 0; i<=loadingTime; i++) {
          //setTimeout(() => {this.value = Math.round((i / loadingTime)*100)}, 15000);
          this.value = Math.round((i / loadingTime)*100)
          this.$forceUpdate()
          await this.timeout(1000)
          //await sleep(1000);
      }
    }
  },
  computed: {
    currentTabComponent: function() {
      return this.componentMatcher[this.currentTab]
    },
    tabChange: function() {
      if (this.prevTab != this.currentTab) {
        this.wait()
        return true
      }
      return false
    }
  }
}
</script>


this.$forceUpdate() // What's this, will this cause re-rendering?

I think, never tested. The pivot component should $emit an event to tell the parent control that it’s done.
There’s no need to use setTimeOut (it’s wrong to me).