$ cd ~/talks/profiling-javascript-performance

Profiling JavaScript Performance⁠

A beginner's tour of the Chrome profiler: finding bottlenecks in your JavaScript without leaning on console.log.

$ open slides

  1. Profiling JavaScript Performance
  2. Welcome
  3. Luke DeWitt EAST COASTER / HUSBAND / FATHER OF 3 UNDER 5 (TIRED) / DEVELOPER / DIRECTOR OF WEB SERVICES Greetings!
  4. JavaScript • Performance is important • Everyone loves fast sites • JS continually redefining itself • Low barrier to entry • Simple to learn • Frameworks
  5. JavaScript ❤❤"
  6. Let’s Dive In
  7. JavaScript • The problems are the same, front or back end
  8. JavaScript • Single threaded • One “chunk” at a time
  9. But Luke!
  10. JavaScript • Single threaded • One “chunk” at a time • Avoid blocking code
  11. JavaScript • Blocking Code • Render blocking • Unresponsive UIs • Accessibility Issues • Bad UX
  12. Call Stack
  13. Call Stack • This is our “single thread” • Last In, First Out • Code added when called (stack frame) • Popped off when “returned” • Repeat until empty • Do it again
  14. The Call Stack call stack function1() function2() function3() function4() function5()
  15. Call Stack Example call stack go() start() andThen() andThenMore() andFinally() console.log()
  16. node --inspect app.js node --inspect-brk app.js
  17. Profile Graph
  18. Recursion Example call stack recursion() recursion() recursion() recursion() recursion() recursion() recursion() recursion() recursion() recursion() recursion() recursion() recursion() recursion() recursion()
  19. Recursion Example call stack recursion() recursion() recursion() recursion() recursion() recursion() recursion() recursion() recursion() recursion() recursion() recursion() recursion() recursion() recursion()
  20. Example
  21. Call Stack Example call stack console.log() cube() parseInt()
  22. Call Stack Example call stack console.log() cube()
  23. Call Stack Example call stack console.log() cube()
  24. Profile Graph
  25. JavaScript
  26. JavaScript • APIs are exposed • Timers • Callbacks • Promises • Async/Await • Limits “Blocking” code • setTimeout === window.setTimeout
  27. Event Loop • Responsible for pushing items onto the Call Stack • Responsible for executing the top most stack frame • Runs when the stack is empty • Also responsible for pulling stack frames from the queue(s) onto the Call Stack for execution
  28. • Implemented by the browsers / node runtime • “Web APIs” for browsers • C++ for node • Essentially act as threading mechanisms • Better code execution • Multiple Queues External APIs
  29. JavaScript call stack queue event loop function1() function2() function3() external apis
  30. JavaScript call stack queue event loop external apis setTimeout(myCB)
  31. JavaScript call stack queue event loop external apis timer(myCB)
  32. JavaScript call stack queue event loop external apis myCB()
  33. XHR & Promise Example
  34. XHR & Promise Graph
  35. XHR & Promise Graph (Request)
  36. XHR & Promise Graph ( Response)
  37. XHR & Async/Await Example
  38. ... tooling...
  39. console.log
  40. console.profile console.profileEnd
  41. Example
  42. Example Graph
  43. Example
  44. Moment of Truth
  45. Open Source https://dewey.codes
  46. Project at a Glance • Started building it in 2014 • Domain knowledge / interest existed • Learning project • Hard deadline • … rushed
  47. The Sandbox
  48. Current Code (API Call)
  49. Profile Graph (API Call)
  50. Profile Graph (API Call) Time To Actual Request Index
  51. Profile Graph (API Call) TTARI 22.387ms TTARI SD 0.514ms
  52. Current Code (API Call)
  53. MOAR OPEN SOURCE!!
  54. Updated Code (API Call)
  55. Profile Graph (API Call w/ Axios) 18.4ms 1.09ms TTARI TTARI SD
  56. TTARI Axios 18.4 ms Request 22.387 ms 18 Improvement o o
  57. We can do better…
  58. Vanilla Code (API Call)
  59. Profile Graph (API Call w/ Vanilla JS) 15.9ms 0.535ms TTARI TTARI SD
  60. TTARI Axios 18.4 ms Request 22.387 ms Vanilla 15.9 ms 29 Improvement o o
  61. TWENTY-NINE
  62. Thank you for coming!
  63. redspace.com / T (902) 444.3490 FACEBOOK REDspace TWITTER @theREDspace LINKEDIN The REDspace LUKE DEWITT @whatadewitt Thank You!
  64. Thank You! Oh, by the way, we’re hiring! https://www.redspace.com/jobs
1 / 70
download pdf ↓

$ cat notes.md

JavaScript has a low barrier to entry, which is great, and it’s also why so much slow JavaScript ships without anyone noticing. This talk was a beginner’s look at the profiler, so you can find the slow parts instead of guessing at them.

How JavaScript runs

  • It’s single threaded: one chunk of work at a time. Blocking code means render blocking, unresponsive UIs, accessibility issues and a bad experience.
  • The call stack is that single thread. Calls push a frame on, returns pop it off, last in, first out, until the stack is empty.
  • Timers, callbacks, promises and async/await hand work to external APIs (Web APIs in the browser, C++ in Node). When it’s done, the callback waits in a queue, and the event loop moves it onto the call stack once the stack is empty.

Profiling it

  • In Node, start your app with node --inspect app.js (or --inspect-brk to pause on the first line) and attach Chrome DevTools.
  • The profile graph shows the call stack over time, so you can see what ran, for how long, and what called it.
  • Wrap the code you care about in console.profile() and console.profileEnd() to record just that part, instead of sprinkling console.log everywhere.

Moment of truth

Then I profiled my own open source project, the Yahoo Fantasy Sports API library. I started it in 2014 as a learning project with a hard deadline, so… it was rushed. Using its sandbox, I measured the time from calling the library to the actual request going out:

VersionTime to request
Original (request)22.4 ms
Axios18.4 ms (18% faster)
Vanilla JS15.9 ms (29% faster)

Twenty-nine percent, just by profiling code I thought I already knew.

visitor@whatadewitt: ~