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

JavaScript Best Practices for Performance and M...

JavaScript Best Practices for Performance and Memory

Some common but poor practices used in Javascript programming can result in memory and performance issues, especially in large-scale and/or single-page apps and websites. We will discuss better practices as well as techniques for the refactoring of problematic existing code.

Avatar for K. Devin McIntyre

K. Devin McIntyre

September 21, 2017
Tweet

More Decks by K. Devin McIntyre

Other Decks in Programming

Transcript

  1. • Causes of performance issues • Principles for high-performing code

    • Finding a balance • Techniques for fixing specific issues • References
  2. Inefficiencies at scale Some techniques work best at small scales

    and others at large scales. • Number of operations • Size of data • Frequency of use
  3. Memory issues Engines optimize memory for you but may lose

    optimization as complexity increases.
  4. Memory issues: GC Garbage collection throws out unreachable objects only.

    JS execution scope Document DOM Tree DIV LI UL LI A Unreachable objB objA objB
  5. Memory issues: GC Garbage collection occurs during a lull sometime

    after you have released some references. • Node: launch with --expose-gc and then use global.gc()
  6. Memory bloat: DOM DOM references may be bigger than you

    think. JS execution scope Document DOM Tree DIV LI UL Detached DOM Tree
  7. Memory bloat: DOM DOM references may be bigger than you

    think. JS execution scope DIV LI UL Detached DOM Tree Document DOM Tree
  8. Memory leaks Memory leaks occur when you fail to remove

    reachable references to something that’s meant to be discarded.
  9. Memory leaks • asynchronous callbacks • event listeners • transient/temporary

    objects • elements removed from or never put in DOM
  10. Memory leaks: DOM DOM objects can create large memory leaks.

    JS execution scope DIV LI UL Detached DOM Tree Document DOM Tree
  11. Memory leaks: circular references DOM element S A Pointer Closure

    JS execution scope Document DOM Tree (More DOM elements) (linked list of S)
  12. Principles: Keep References Close Use a modular organization that keeps

    functions, scopes, and objects as small as possible, each containing only what's needed.
  13. Principles: Keep References Close If possible, use a framework that

    provides dependency injection of some kind.
  14. Principles: Keep References Close When using closures, put variables in

    the lowest possible scope where they are reachable by whatever needs them. global~scope .makePresentation~scope .presentation global~scope .makePresentation~scope .setPresentation~scope .size
  15. Principles: Keep References Close Minimize what is held in memory

    for asynchronous callbacks and event listeners.
  16. Principles: Keep References Close Keep prototype/inheritance chains short and the

    number of properties low for frequently- used objects.
  17. Principles: DOM Mindfulness Add minimal JS code to DOM elements,

    especially expando objects and functions.
  18. Finding a balance Constraining your team’s techniques based solely on

    performance can affect creativity and confidence among developers.
  19. Finding a balance The best performing technique is not always

    the most readable one or the easiest to implement and maintain.
  20. Finding a balance No simple performance test (e.g. JSPerf) can

    reliably tell you what’s right for your code.
  21. Finding a balance 1. Follow the principles of Least Change,

    Keep References Close, and DOM Mindfulness. 2. Identify performance bottlenecks in your app regularly and iteratively. 3. Apply known performance tricks to bottlenecks and move on quickly. 4. Only long-term bottlenecks should receive extra attention and research.
  22. Best techniques: small functions (any performance issue) Use small, simple

    functions, and use pure functions when possible. Then reuse them.
  23. Best techniques: classes (memory leak, frequently-used object) Use defined object

    types/classes for the majority of your objects, starting with the largest and the most frequently used objects.
  24. Best techniques: named functions (memory bloat or leak) Use names

    for any functions that declare an object type or that have closures inside, so you can track their memory use. • function nameIsHere () ….. • var varName = function nameIsHere () ….. • NOT var varName = function () …..
  25. Best techniques: auto-destruct (memory leak) Whenever a reference to or

    from a DOM element is created, an automatic destroyer is also created that ensures destruction of those references.
  26. Best techniques: bind (memory issues from async callbacks) Use `bind`

    to limit the amount of memory needed for an asynchronous callback, or to prevent creating excess closures.
  27. Techniques: limited closure (memory issues from async callbacks) Use a

    smaller function to limit the closures needed for an asynchronous callback.
  28. Techniques: local pointer (slow closures) If a variable from two

    or more rungs up the scope chain is accessed more than once, provide it a local variable within the current scope. Global function makePresentation function setParticipants function checkValidity if(presentation.participants > presentation.room.capacity) { ….. *more code here+ …..
  29. Techniques: local pointer (slow closures) If a variable from two

    or more rungs up the scope chain is accessed more than once, provide it a local variable within the current scope. Global function makePresentation function setParticipants function checkValidity var _presentation = presentation; if(_presentation.participants > _presentation.room.capacity)
  30. Techniques: iteration of property array (object iteration bottleneck) If you

    know them, iterate over arrays of specific properties, rather than over objects of unknown or large sizes.
  31. Techniques: efficient CSS (slow repaint/reflow) Use efficient CSS selectors and

    remember the browser reads combinations of them from right to left. Most efficient, in order: 1. ID or class 2. Type, e.g. div 3. Adjacent sibling 4. Child 5. Descendant
  32. Techniques: bubble-up events (memory bloat and leaks) 1. Make an

    event system object where you register callbacks based on event type and some property on the element (e.g. id, class). 2. On the parent node, create one listener for each kind of event. This listener should call your registered callbacks based on event type and the same property on event.target, then iterating upward through event.target.parentNode. 3. Because events bubble up, events on the children will reach the parent node’s listeners.
  33. Techniques: V8 optimized type (frequently-used object) For frequently-used objects, don’t

    use the “delete” keyword and don’t add properties that aren’t in the prototype/class definition.
  34. Techniques: lookup table (large scale conditional) Instead of making a

    long conditional, use an object with each conditional outcome as values.
  35. Techniques: conditional advance loading (frequent conditional) For unchanging conditionals, swap

    out different functions rather than using conditional statements.
  36. Techniques: memoization (large, complex bottleneck) Cache the results of functions

    based on their arguments. (This requires pure functions.) From https://en.wikipedia.org/wiki/Memoization
  37. Techniques: object pool (GC stutter) 1. Make an array containing

    only objects of a specific type/class. 2. Pool accessor function first searches for an unused instance in the array, then creates one and adds it if needed.
  38. Techniques: loop unrolling (enormous number of iterations) This uses a

    switch statement inside the loop so that the end condition of the loop gets evaluated less frequently. https://en.wikipedia.org/wiki/Loop_unrolling
  39. Techniques: backwards loop (large number of iterations) If backwards iteration

    will work, writing the loop so the end condition and the iteration step are the same thing provides slightly less overhead. for (var i = array.length-1; i--; )
  40. Techniques: webworker (long-running computation) Put long-running computations that hold up

    execution into a separate “thread” or webworker. https://www.html5rocks.com/en/tutorials/workers/basics/ https://medium.com/@roman01la/run-web-worker-with-a- function-rather-than-external-file-303add905a0
  41. References: general • Zakas, Nicholas. High Performance Javascript: Build Faster

    Web Application Interfaces. Yahoo Press. 2010. • https://developers.google.com/speed/articles/optimi zing-javascript • https://www.smashingmagazine.com/2016/12/front- end-performance-checklist-2017-pdf-pages/ • https://www.smashingmagazine.com/2014/09/impro ving-smashing-magazine-performance-case-study/ • https://csswizardry.com/2011/09/writing-efficient- css-selectors/ • https://en.wikipedia.org/wiki/Memoization
  42. References: memory • https://docs.google.com/presentation/d/1wUVmf78gG- ra5aOxvTfYdiLkdGaR9OhXRnOlIcEmu2s/pub?start=false&loop=false&del ayms=3000&slide=id.g322f9af_0_86 • https://github.com/felixge/node-memory-leak-tutorial • https://developer.mozilla.org/en-

    US/docs/Web/JavaScript/Memory_Management#Cycles_are_not_a_pro blem_anymore • https://www.smashingmagazine.com/2012/11/writing-fast-memory- efficient-javascript/ • https://medium.com/outsystems-experts/beyond-memory-leaks-in- javascript-d27fd48ae67e • https://stackoverflow.com/questions/18521254/cant-seem-to-cleanup- detached-dom-elements • https://developers.google.com/web/tools/chrome-devtools/memory- problems/ • https://stackoverflow.com/questions/8032928/can-i-trigger-javascripts- garbage-collection