Home > database >  Reduce function works but takes too long, vue
Reduce function works but takes too long, vue

Time:11-18

In my Vue app, I have a reduce function that's being called within an html/vue loop and it's taking far too long; around 21 seconds

During that time, nothing renders and the page freezes temporarily

I think part of the issue is that I'm calling the computed property in a loop and it calls the reduce function each time, but I'm still unclear on a way to optimize this to quickly go through the reduce function and allow the loop to only hit the result set as opposed to reducing through each iteration.

My result set is about 12,000 records but I've only included a few in the exact structure.

What can I do here?

<script>
const reduceFunction = (rows) =>
  rows .reduce(
    (a, row) => {
      const employee = a [row .employee] || (a [row .employee] = {dates: {}, total_categories:0, total_items: 0, area: '', group: ''})
      const date = employee .dates [row .itemDate] || (employee .dates [row .itemDate] = {categories: 0, qty: 0, total_categories: 0, unavailable: 0, orders: {}})

      date.categories  =  row.categories_per_item *  row.qty
      date.qty  =  row.qty

      date.total_categories = date.categories

      const order = date .orders [row .order_number] || (date .orders [row .order_number] = {itemDate: '', skus: {}})

      order.itemDate = row.itemDate;

      const sku = order .skus [row .sku] || (order .skus [row .sku] = {categories: '', qty: '', itemDate: '', expected: '', created: '', unavailable: 0, available:0})

      sku.categories  = row.categories_per_item
      sku.qty  = row.qty
      sku.itemDate = row.itemDate
      sku.expected = row.shipDate
      sku.created = row.created_date
      sku.heir_id = row.heir_identifier

      employee.total_categories  = ( row.categories_per_item *  row.qty)
      employee.total_items  = ( row.qty)
      employee.area = row.area
      employee.group = row.group_name
      employee.warehouse = row.warehouse 
      employee.locale = row.locale


      const foundKit = vm.$data.kitsData.find((kit) => kit.heir_identifier === sku.heir_id)

      if (foundKit) {

        new_avail = 10;

        if(sku.qty > new_avail){
          status.status = "Not available";
          date.unavailable  = 1
          sku.unavailable  = 1
        }else{
          status.status = "Available"
        }
      }else{
        status.status = "No item found"
      }

      return a
    },
    {}
  );


var vm = 
new Vue({
  el: "#app",

  data: {
    rows: [
            {  
                employee: "Adam",
                sku: "A1453",
                categories_per_item: "15",
                area: "1",
                itemDate: "2021-11-02",
                qty: 37,
                group_name: "managers",
                warehouse: "3",
                order_number: "1234",
                locale: "1",
                shipDate: "2020-02-02",
                created_date: "2020-01-01",
                heir_identifier:"ABC3"
            },
            {  
                employee: "Joan",
                sku: "A1453",
                categories_per_item: "15",
                area: "1a",
                itemDate: "2021-11-02",
                qty: 17,
                group_name: "managers",
                warehouse: "3",
                order_number: "34578",
                locale: "1",
                shipDate: "2020-02-02",
                created_date: "2020-01-01",
                heir_identifier:"ABC3"
            },
            {  
                employee: "Bill",
                sku: "A1453",
                categories_per_item: "15",
                area: "1",
                itemDate: "2021-11-03",
                qty: 57,
                group_name: "managers",
                warehouse: "3",
                order_number: "2345",
                locale: "1",
                shipDate: "2020-02-02",
                created_date: "2020-01-01",
                heir_identifier:"ABC3"
            },
            {  
                employee: "PJ",
                sku: "A6512",
                categories_per_item: "150",
                area: "2",
                itemDate: "2021-11-03",
                qty: 20,
                group_name: "managers",
                warehouse: "3",
                order_number: "34567",
                locale: "1",
                shipDate: "2020-02-02",
                created_date: "2020-01-01",
                heir_identifier:"ABC1"
            }
        ]
  },
  methods: {

  },

  computed: {
    employeeData() {
      console.log('employee data')
      employeeRows = reduceFunction(this.rows)
      return employeeRows
      console.log(employeeRows)
    },

    dates() {
      return Array.from(Array(11), (_, i) => new Date(Date.now()   i * 86400000).toISOString().slice(0,10))
    }
    
  }
});


</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
<tr v-for="(value, employee) in employeeData"  :key="employee">
  <td>@{{employee}}</td>
  <td v-for="date in dates" :key="date" >
    <div v-for="(dateInfo, dateValue) in value.dates" :key="dateValue" >
      <div v-if="dateValue == date ">
       
        @{{ dateInfo.total_categories }}
      
      </div>
    </div>
  </td>
</tr>
</div>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

The main improvement I could see would be to eliminate the nested loop here:

const foundKit = vm.$data.kitsData.find((kit) => kit.heir_identifier === sku.heir_id)

Organize the kitsDat by heir_identifier first so you can look up in O(1) instead of .finding (O(n)) each time.

const kitsByHeir = new Map();
for (const kit of vm.$data.kitsData) {
  kitsByHeir.set(kit.heir_identifier, kit);
}

Then do kitsByHeir.get(sku.heir_id) inside the loop.

You might also use a for loop instead of reduce (reduce is arguably not appropriate in this situation anyway)

Also, processing 12,000 records on the client-side is pretty odd. Even with the best designed code, that could take an uncomfortable amount of time in certain environments. Consider moving the processing to a server instead.

CodePudding user response:

My approach for this problem would be to invoke reduceFunction on mounted(){} and create another state for the array, here I called it parsedRow So basically to avoid unnecessary re rendering.

 
data: {
  rows: []
  parsedRows: []

}
methods: {
  reduceFunction(data){
     //adjust your code to fit method here
  }
}
mounted(){
  this.parsedRows = this.reduceFunction(this.rows);
}

and then use the parsedRows on the Vue template. Also to move the reduceFunction to methods

  • Related