class: center, middle # Node.js feature livecoding Anna Henningsen
she/her
@addaleax Slides @ https://addaleax.net/livecoding-jsfest19/
--- # Who am I? - Active Node.js contributor since December 2015 - Working full-time on Node.js at NearForm - Involved in Cool Stuff™ like Workers, HTTP2, brotli, `util.promisify()`, … - Currently: A lot of QUIC/HTTP3 - Cares about spreading knowledge about Node.js internals! --- name: how-did-i # How did I get into Node.js core? ```js setTimeout(1000, 1000, function() { console.log('hi!'); }); ``` --- template: how-did-i (don’t ask me why) ``` > TypeError: callback.call is not a function at ontimeout [as _onTimeout] (timers.js:195:34) at Timer.listOnTimeout (timers.js:92:15) ``` --- template: how-did-i ```diff @@ -177,6 +177,10 @@ exports.enroll = function(item, msecs) { exports.setTimeout = function(callback, after) { + if (typeof callback !== 'function') { + throw new TypeError('"callback" argument must be a function'); + } + after *= 1; // coalesce to number or NaN if (!(after >= 1 && after <= TIMEOUT_MAX)) { ``` --- # Node.js feature: setTimeout() #### Where does `setTimeout()` come from??? -- (Hint: It’s *not* the language!)
--- # Node.js feature: setTimeout() - `setTimeout()`: Managed by event loop → libuv ```js const socket = net.connect(80, 'google.com', () => { console.log('connected'); }); setTimeout(() => { socket.end(); }, 1000); ``` --- # Node.js feature: setTimeout() - `setTimeout()`: Managed by event loop → libuv - libuv central concepts: handles vs requests - `uv_handle_t`: Long-lasting, multi-event (e.g. net Socket) - `uv_req_t`: Oneshot (e.g. net connect, fs ops) - libuv provides timers as … -- 🛑 **handles** 🛑 --- # Data stored for a timer - Actual timeout function - libuv data (`uv_timer_t`) - includes event loop, timeout duration, native callback, etc. - C++ object - JS object - Async tracking --- name: helper-classes # Node.js internal helpers in fake JS --- template: helper-classes ```js class MemoryRetainer { constructor() {} /* ... */ } ``` C++ objects that show up in heap dump --- template: helper-classes ```js class BaseObject extends MemoryRetainer { constructor(env, jsObject) { this.env = env; this.jsObject = jsObject; } /* ... */ } ``` JS ↔ C++ binding connection --- template: helper-classes ```js class AsyncWrap extends BaseObject { constructor(env, jsObject, providerType) { /* run 'init' async hooks */ } MakeCallback(functionName, arguments) { /* run 'before' async hooks */ this.jsObject[functionName](...arguments); /* run 'after' async hooks + nextTick queue + µTask queue */ } } ``` C++ objects that enter JS on their own --- template: helper-classes ```js class ReqWrap extends AsyncWrap { constructor(env, jsObject, libuvRequest, providerType) { /* ... */ } /* ... */ } class HandleWrap extends AsyncWrap { constructor(env, jsObject, libuvHandle, providerType) { /* ... */ } ref() { /* ... */ } unref() { /* ... */ } close() { /* ... */ } } ``` Associated with libuv requests / handles --- # What we want to write in C++ (in JS) ```js class TimerWrap extends HandleWrap { constructor(env, jsObject) { super(env, jsObject, this.timer, PROVIDER_TIMER); this.timer.init(env.event_loop()); } start(timeout_ms) { this.timer.start(TimerWrap.Callback, timeout_ms, 0); } static Callback(timer) { timer.MakeCallback('ontimeout', []); } } ``` --- # Node.js layers
setTimeout()
Operating System
↓
↑
lib/timers.js
libuv | Event Loop
↓
↑
internalBinding('timers')
→
src/timers.cc
--- # Thank you! Now for the exciting part :) - https://twitter.com/addaleax/ Slides @ https://addaleax.net/livecoding-jsfest19/ --- # A note on performance ``` $ ./node benchmark/timers/timers-timeout-unpooled.js timers/timers-timeout-unpooled.js impl="cool" n=1000000: 980,551.584937205 timers/timers-timeout-unpooled.js impl="boring" n=1000000: 12,039,297.470874682 ``` 😳 -- Node’s `setTimeout()` implementation is highly optimized! - Fewer C++ ↔ JS boundary crossings - Grouping timers with the same duration - Calling nextTick from JS - … and more --- # Thank you! - https://twitter.com/addaleax/ Slides @ https://addaleax.net/livecoding-jsfest19/