Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Profiling emberjs apps

Profiling emberjs apps

Selva Ganesh

August 07, 2018
Tweet

Other Decks in Programming

Transcript

  1. Load performance 1. TTFP (time taken for first paint; increases

    perceived performance) 2. TTFI (time taken for first meaningful interaction) Runtime performance 1. Rendering (jank-free 60 fps) 2. Memory monitoring
  2. Memory Management JS engine does automatic memory allocation. So, we

    don’t have any role to play So, we don’t have any role to play
  3. Everything on memory are not leaks. In ember world, ideally

    you’d want to look for `destroyed` objects being held Few profiling tips Force garbage collection before taking snapshots Always use Incognito/Guest window Identify & measure the leaks before fixing it
  4. • Prototypal state leakage • Event listeners leakage • Third

    party libs • window.set*/Ember.run* timers • Module scope leakage • Global leakage In ember.js apps
  5. export default Component.extend({ init() { this._super(...arguments); this.set('tags', []); }, actions:

    { addTag(tagName) { this.tags.pushObject(tagName); }, }, }); export default Component.extend({ tags: [], actions: { addTag(tagName) { this.tags.pushObject(tagName); }, }, });
  6. export default Component.extend({ didInsertElement() { this._super(...arguments); this._closeModal = this.closeModal.bind(this); window.addEventListener('keydown',

    this._closeModal); }, willDestroyElement() { this._super(...arguments); window.removeEventListener('keydown', this._closeModal); }, closeModal(event) { if (event.which === 27) { this.onClose(); } } }); export default Component.extend({ didInsertElement() { this._super(...arguments); window.addEventListener('keydown', this.closeModal.bind(this)); }, willDestroyElement() { this._super(...arguments); window.removeEventListener('keydown', this.closeModal); }, closeModal(event) { if (event.which === 27) { this.onClose(); } } });
  7. export default TextField.extend({ didInsertElement() { this._super(...arguments); this.$().selectize({ delimiter: ',', create:

    function(input) { return { value: input, text: input }; } }); }, }); export default TextField.extend({ didInsertElement() { this._super(...arguments); this.$().selectize({ delimiter: ',', create: function(input) { return { value: input, text: input }; } }); }, willDestroyElement() { this._super(...arguments); this.$()[0].selectize.destroy(); } });
  8. export default Component.extend({ didInsertElement() { this._super(...arguments); this.setTimeoutId = setTimeout(() =>

    { // this.doSomeStuffs() }, 1000); this.runTimerId = Ember.run.later(() => { // this.doSomeStuffs() }, 1000); }, willDestroyElement() { this._super(...arguments); clearTimeout(this.setTimeoutId); Ember.run.cancel(this.runTimerId); } }); export default Component.extend({ didInsertElement() { this._super(...arguments); setTimeout(() => { // this.doSomeStuffs() }, 1000); Ember.run.later(() => { // this.doSomeStuffs() }, 1000); }, });
  9. const UNIQUE_OPTIONS_COUNTER = new Map() export default Component.extend({ options: UNIQUE_OPTIONS_COUNTER,

    actions: { addFooToOptions() { this.options.set(this, 'foo') } } }); export default Component.extend({ init() { this._super(...arguments); this.set('options', new Map()); }, actions: { addFooToOptions() { this.options.set(this, 'foo') } } });
  10. Summarising - Clear all timers/event listeners/third-party libs - Don’t pass

    the entire controller/component references around (yield the component’s public api using hash helper) - Do not set non-primitives on prototypes - Don’t increase the scope of your objects