减少功能有效,但需要太长时间,vue
Posted
技术标签:
【中文标题】减少功能有效,但需要太长时间,vue【英文标题】:Reduce function works but takes too long, vue 【发布时间】:2021-12-28 00:41:01 【问题描述】:在我的 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>
【问题讨论】:
您是否尝试将 renderFunction 移动到methods:
?
你的意思是reduceFunction
?我绝对可以,如果这会以任何方式表现得更好
【参考方案1】:
我解决这个问题的方法是在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
【讨论】:
【参考方案2】:我能看到的主要改进是消除这里的嵌套循环:
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 条记录也很奇怪。即使使用设计最好的代码,在某些环境中也可能会花费大量时间。请考虑将处理转移到服务器。
【讨论】:
我认为问题是 21 秒,只有 4 条记录。因此 O(n) 不会比 O(1) 相差太多 他说12,000条记录是21秒(问题中只包含了几条记录,只是为了举例说明数据结构) OPs 问题,正如他所说,可能与改变依赖于该值的计算属性内的行的值有关,然后在渲染输出中使用该值;这将导致大量的重新渲染周期。修改计算属性和监视属性中的值时,很容易导致无限循环。 我在控制台中做了一个小测试,看起来 12k 行可以节省 2-3 秒,这很重要!但是,可能不是 OPs 问题的原因。考虑优化单个嵌套循环的理论上的最坏情况时间复杂度听起来非常好(这里不讽刺!),但我不确定它在很多情况下会产生巨大的差异,尤其是在前面 -结束 JS 当你通常不处理大量记录时,特别是当你考虑到你编写的代码通常会经过一个转译器,然后由 JS 引擎进一步处理和优化。 一般来说,这不是您所争论的 ^_^ 只是给我 2 美分。我同意在前端处理 12k 记录是不寻常的。我希望这些记录在进入管道之前在后端进行处理。以上是关于减少功能有效,但需要太长时间,vue的主要内容,如果未能解决你的问题,请参考以下文章