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)
中查找,而不是每次都 .find
ing (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
循环代替 reduce
(reduce
可以说是 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
在我的 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)
中查找,而不是每次都 .find
ing (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
循环代替 reduce
(reduce
可以说是 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