Fun with async hooks and stack traces

@naugtur, 2020
## Goal: ### Nerdy amusement with a chance of education # ๐Ÿ‘‡ Click for yourself: https://naugtur.pl https://github.com/naugtur/debugging-aid-demo
[![](CliffordStoll_2006-embed.jpg)](https://www.ted.com/talks/clifford_stoll_the_call_to_learn?utm_campaign=tedspread&utm_medium=referral&utm_source=tedcomshare) It's going to be like this TED talk by Clifford Stoll if all goes well...
## I've got unusual hobbies
## ๐Ÿง™ ### Trying seemingly impossible things in JavaScript is fun
But first!
## ๐Ÿ“ฃ Introoo
# ๐ŸŽฃ ## Async hooks? ```js const asyncHooks = require('async_hooks'); const hook = asyncHooks.createHook({ init, before, after, destroy }); hook.enable(); ```
### init ```js Promise.resolve() .then(๐Ÿ‘‹() => { return doingWork() }) ``` Runs within current call stack
### before ```js Promise.resolve() .then(() => ๐Ÿ‘‹{ return doingWork() }) ```
### after ```js Promise.resolve() .then(() => { return doingWork() }๐Ÿ‘‹) ```
### destroy ```js Promise.resolve() .then(() => { return doingWork() }) ... ๐Ÿ‘‹ ```
There's also `promiseResolve` one now. But instead of repeating documentation, I'll link to something you won't find in the docs: https://github.com/nodejs/node/tree/master/deps/v8/test/mjsunit/async-hooks
## ๐Ÿงช ๐Ÿ’ฅ ## experiments!
# ๐Ÿค” > How many promise objects do I produce?
```js const functions = [inc,inc,inc] const result = functions.reduce( async (acc, f) => await f(await acc), Promise.resolve(1) ) const result = functions.reduce( (acc, f) => acc.then(f), Promise.resolve(1) ) ```
```js const functions = [inc,inc,inc] const result = functions.reduce( async (acc, f) => await f(await acc), Promise.resolve(1) ) // 14 const result = functions.reduce( (acc, f) => acc.then(f), Promise.resolve(1) ) // 5 ```
```js let count = 0; const asyncHooks = require('async_hooks'); const asyncHook = asyncHooks.createHook({ init(asyncId, type, triggerAsyncId) { if (type === 'PROMISE') count++; }, }); asyncHook.enable(); process.on('beforeExit', () => { console.log(`promises created: ${count}`); }); ```
This and other little experimental tools can be found in [debugging-aid package](https://www.npmjs.com/package/debugging-aid)
# ๐Ÿค” > Can I find the function that blocks the event loop?
```js const timers = {} before:(asyncId) => { timers[asyncId] = Date.now() } after:(asyncId) => { synchronousRunTime = Date.now() - timers[asyncId] } //you may be disappointed if you actually use Date.now() ```
### Ok, now which function was it?
```js function whereAmI(){ const e = {} Error.captureStackTrace(e) return magicParsing(e.stack) } ``` ``` /home/naugtur/repo/app/app.js:14:4 ``` # ๐Ÿ†
### Demo and deep dive This functionality is available in a standalone package `blocked-at` [see the file with hooks](https://github.com/naugtur/blocked-at/blob/master/index.js#L25)
# ๐Ÿค” > Can I see which modules are using network?
```py [aid] network, outgoing to: http://example.com/ stack: at Agent.createSocket (_http_agent.js:265:26) at Agent.addRequest (_http_agent.js:224:10) at new ClientRequest (_http_client.js:296:16) at Object.request (http.js:46:10) at Request.start (node_modules/request/request.js:751:32) at Request.end (node_modules/request/request.js:1511:10) ```
# ๐Ÿฟ > Bonus - control network access for modules [package-firewall](https://github.com/naugtur/package-firewall)
# ๐Ÿค” > Can I visualize asynchronous flow of my app?
There's better tools for that, but hey - why not! ## DEMO

Thanks for participating
in my hobbies



@naugtur   naugtur.pl

Q&A or more demos?