Vue.js Vue模板中的匿名函数是性能杀手吗?
我有以下设置: 在子组件中:Vue.js Vue模板中的匿名函数是性能杀手吗?,vue.js,templates,anonymous-function,emit,Vue.js,Templates,Anonymous Function,Emit,我有以下设置: 在子组件中: <template> <div @click="clickHandler"> </div> </template> <script> ... clickHandler() { this.$emit('emittedFunction', someInfo, otherInfo) } </script> ... clickHandler()
<template>
<div @click="clickHandler">
</div>
</template>
<script>
...
clickHandler() {
this.$emit('emittedFunction', someInfo, otherInfo)
}
</script>
...
clickHandler(){
此.$emit('emittedFunction',someInfo,otherInfo)
}
在父组件中:
<template>
<child-component
v-for="index in 10"
@emittedFunction="(someInfo, otherInfo) => someFunction(index, someInfo, otherInfo)"/>
</template>
<script>
...
someFunction(index, someInfo, otherInfo) {
do stuff
}
</script>
...
someFunction(index,someInfo,otherInfo){
做事
}
这段代码运行得非常好。但我的一个问题是:我的一个朋友看到了这个代码片段,并在评论中说,“Vue模板中的匿名函数是性能杀手”,我应该用另一种方式来做……他显然没有解释如何做。
我在vue文档或堆栈溢出中找不到有关此主题的任何内容。我也不明白为什么这种代码会“杀死”性能?
他说得对吗?若有,原因为何?若否,原因为何?如果我的代码真的不好,有没有办法重构它
谢谢你的帮助 您的朋友指的是这样一个事实,即编译模板以呈现函数,这些函数在每次重新呈现时都会运行 他们所指的问题是,由于每个渲染中的处理程序不同,分配匿名函数的开销很小,这意味着Vue无法重用处理程序,并导致它使用侦听器重新渲染节点 这确实可能会带来性能问题,但不太可能因此而遇到或编写速度较慢的代码。通常情况下,如果组件重新渲染的频率太高,那么开销会变得很明显,这意味着您应该修复重新渲染触发器,而不是修复此触发器 因此,我不会说它是“性能杀手”,而是更像一个“优化机会” 为了安全起见,您可以使用闭包对其进行重构,如下所示:
<template>
<child-component
v-for="index in 10"
@emittedFunction="someFunction(index)(someInfo, otherInfo)"
/>
</template>
<script>
...
someFunction(index) {
return (someInfo, otherInfo) => {
// this is a closure, you have access to the index.
};
}
</script>
...
函数(索引){
返回(someInfo,otherInfo)=>{
//这是一个闭包,您可以访问索引。
};
}
虽然这看起来很奇怪,但它不会在每次渲染时创建新函数,它只会在发出事件时创建一个新函数,并且它与渲染无关。您的朋友指的是,模板被编译为渲染函数,渲染函数在每次重新渲染时运行 他们所指的问题是,由于每个渲染中的处理程序不同,分配匿名函数的开销很小,这意味着Vue无法重用处理程序,并导致它使用侦听器重新渲染节点 这确实可能会带来性能问题,但不太可能因此而遇到或编写速度较慢的代码。通常情况下,如果组件重新渲染的频率太高,那么开销会变得很明显,这意味着您应该修复重新渲染触发器,而不是修复此触发器 因此,我不会说它是“性能杀手”,而是更像一个“优化机会” 为了安全起见,您可以使用闭包对其进行重构,如下所示:
<template>
<child-component
v-for="index in 10"
@emittedFunction="someFunction(index)(someInfo, otherInfo)"
/>
</template>
<script>
...
someFunction(index) {
return (someInfo, otherInfo) => {
// this is a closure, you have access to the index.
};
}
</script>
...
函数(索引){
返回(someInfo,otherInfo)=>{
//这是一个闭包,您可以访问索引。
};
}
虽然这看起来很奇怪,但它不会在每个渲染上创建新函数,它只会在发出事件时创建一个新函数,并且它与渲染无关。这样写不需要Vue为每个节点生成一个内部包装函数吗,这么说,你又回到了起点了?我不确定Vue到底是如何做到的,但是如果你看看Vue源代码中的
updatelisteners.js
帮助程序。它创建一个特殊的invoker
对象,作为处理程序的调度程序,对于iLife,就像上面代码段中的那样,它只将其添加到invokerfns
中,如果它实际发生更改,它将删除它而不重新呈现节点,否则,它会执行一个简单的==
来检查前一个处理程序是否等于新的处理程序。我认为源代码中更相关的部分是,它根据从v-on
属性解析的字符串值生成render
函数的相关部分。Vue本身需要创建一个包装函数,以便它可以在闭包中保存索引
,并且每次呈现组件时都需要重新创建该函数,以确保它引用的是索引
的最新值。首先感谢您的回答!!不过,这个话题似乎比我预想的更复杂。子组件中的“发射”事件将非常频繁地发射。父组件中的someFunction将更改一些值,这些值作为道具发送回子组件,因此编号为“index”的子组件将在该点重新渲染。但是我假设父组件在那个时候仍然不会完全重新加载?如果我每分钟发出200次“emittedFunction”,是否有办法确定是否会对性能产生影响?这样写不需要Vue为每个节点生成一个内部包装函数,所以实际上你回到了起点?我不确定Vue到底是如何做到的,但是如果您查看Vue源代码中的updatelisteners.js
helper。它创建一个特殊的invoker
对象,作为处理程序的调度程序,对于iLife,就像上面代码段中的那样,它只将其添加到invokerfns
中,如果它实际发生更改,它将删除它而不重新呈现节点,否则,它会执行一个简单的==
来检查前一个处理程序是否等于新的处理程序。我认为源代码中更相关的部分是,它根据从v-on
属性解析的字符串值生成render
函数的相关部分。Vue本身需要创建一个包装器函数,以便它可以在闭包中保存索引
,并且该函数需要