Reduce 函数有效但耗时太长,vue

Reduce function works but takes too long, vue

在我的 Vue 应用程序中,我有一个在 html/vue 循环中调用的 reduce 函数,它花费的时间太长;大约 21 秒

在那段时间里,没有任何内容呈现,页面暂时冻结

我认为部分问题是我在循环中调用计算 属性 并且它每次都调用 reduce 函数,但我仍然不清楚如何快速优化它通过 reduce 函数并允许循环只命中结果集,而不是通过每次迭代减少。

我的结果集大约有 12,000 条记录,但我只包含了其中几条确切的结构。

我可以在这里做什么?

<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>

我能看到的主要改进是消除此处的嵌套循环:

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

首先按 heir_identifier 组织 kitsDat,这样您就可以在 O(1) 中查找,而不是每次都 .finding (O(n))。

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

然后在循环中执行kitsByHeir.get(sku.heir_id)

您也可以使用 for 循环代替 reducereduce 可以说是 not appropriate in this situation anyway

此外,在客户端 处理 12,000 条记录 也很奇怪。即使使用设计最好的代码,在某些环境中也可能会花费令人不舒服的时间。考虑将处理转移到服务器。

我解决这个问题的方法是在 mounted(){} 上调用 reduceFunction 并为数组创建另一个状态,这里我称之为 parsedRows 所以基本上是为了避免不必要的重新渲染。

 
data: {
  rows: []
  parsedRows: []

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

然后在 Vue 模板上使用 parsedRows。 还要将 reduceFunction 移动到 methods