[Vuejs]-Vue.js callback references rather than emits

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>

Leave a comment