2👍
I went ahead and set up a performance test for you.
Listeners are significantly faster than callbacks.
Comparison of 10 callbacks/listeners each called 10 times show that callbacks are between 5% and 15% slower than listeners. The difference in performance increases the more each callback/listener is executed: at 1000 executions callbacks are between 15% and 25% slower.
https://jsperf.com/vuejs-listener-vs-callback/
I’d welcome corrections in case I’ve made any dumb mistakes that make this an unfair test, but so far it appears that the standard $emit / $on pattern is very much preferable in terms of performance to passing around callback props.
This isn’t to say that callbacks should never be used — they can be more convenient in some cases, and might be a more familiar idiom for developers coming from React. But don’t use vague concerns about performance to justify that preference.
The test code
Here’s the code I compared:
Listeners:
For simplicity’s sake I used the common event bus pattern here, rather than communicating directly between components; I don’t believe that would make a significant difference in performance (but welcome corrections if so!)
var bus = new Vue({});
Vue.component('parent', {
template: '<div>Parent {{counter}} <child></child></div>',
data() {return {counter: 0}},
beforeMount() {
// 10 listeners
for (var i=0; i<10; i++) {
window.bus.$on('testemit'+i, () => {
this.counter++;
});
}
}
})
Vue.component('child', {
template: '<div>Child</div>',
mounted() {
// call each listener 10 times
for (var i=0; i<10; i++) {
for (var j=0; j<10; j++) {
window.bus.$emit('testemit'+i);
}
}
}
})
var app = new Vue({
el: '#app'
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.min.js"></script>
<div id="app">
<parent></parent>
</div>
Callbacks:
For fairness between the tests an event bus instance is set up here as well as in the listener test; it’s then ignored in favor of callback props.
var bus = new Vue({});
Vue.component('parent', {
// 10 callback props
template: "<div>Parent {{counter}}<child :c1='foo' :c2='foo' :c3='foo' :c4='foo' :c5='foo' :c6='foo' :c7='foo' :c8='foo' :c9='foo' :c10='foo' ></child></div>",
data() {return {counter: 0}},
methods: {
foo() {
this.counter++
}
}
});
Vue.component('child', {
template: '<div>Child</div>',
props: ["c1","c2","c3","c4","c5","c6","c7","c8","c9","c10"],
mounted() {
// call each callback 10 times
for (var i=0; i<10; i++) {
this.c1();
this.c2();
this.c3();
this.c4();
this.c5();
this.c6();
this.c7();
this.c8();
this.c9();
this.c10();
}
}
})
var app = new Vue({
el: '#app'
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.min.js"></script>
<div id="app">
<parent></parent>
</div>