Skip to content

Instantly share code, notes, and snippets.

@MayaLekova
Last active June 4, 2018 11:13
Show Gist options
  • Save MayaLekova/b58e3acf93a92172d7515d42ac515c4a to your computer and use it in GitHub Desktop.
Save MayaLekova/b58e3acf93a92172d7515d42ac515c4a to your computer and use it in GitHub Desktop.
Tool to draw trees out of async resource ids
const fs = require('fs');
const D3Node = require('d3-node')
const d3n = new D3Node();
const d3 = d3n.d3;
const w = 400, h = 300;
// Draw the contents of the 'root' hierarchy in the 'svg' element
function draw(root, svg) {
// Nodes
let nodes = svg
.selectAll('circle.node')
.data(root.descendants())
.enter()
.append('g')
.classed('node', true);
nodes.append('circle')
.attr('cx', function(d) {return d.x;})
.attr('cy', function(d) {return d.y;})
.attr('r', 4);
nodes.append('text')
.text(function(d) { return d.id; })
.attr('x', function(d) {return d.x + 5;})
.attr('y', function(d) {return d.y;})
.style('font-size', 'x-large');
// Links
svg
.selectAll('line.link')
.data(root.links())
.enter()
.append('line')
.classed('link', true)
.attr('x1', function(d) {return d.source.x;})
.attr('y1', function(d) {return d.source.y;})
.attr('x2', function(d) {return d.target.x;})
.attr('y2', function(d) {return d.target.y;})
.attr('style', 'stroke:lightsteelblue;stroke-width:2');
}
// main pipeline
// 1. construct the hierarchy
// 2. layout this as a tree
// 3. create the SVG and draw into it
// 4. dump into an .svg file
function drawAsyncTree(parsed) {
let root = d3.stratify()
.id(function(d) { return d.id; })
.parentId(function(d) { return d.parent; })
(parsed);
d3.tree().size([w, h])(root);
const svg = d3n.createSVG(w,h+100).append('g')
.attr('transform', `translate(0,50)`);
draw(root, svg);
fs.writeFileSync('output.svg', d3n.svgString(), 'utf8');
}
// parse children[] and parents[] arrays into a hierarchy
function idsParse(children, parents) {
let ret = [];
ret.push({id: 1, parent: undefined});
for (let idx in children) {
ret.push({id: children[idx], parent: parents[idx]});
}
return ret;
}
// Async hooks instrumentation for promises
const async_hooks = require('async_hooks');
let asyncIds = [], triggerIds = [];
let ah = async_hooks.createHook({
init(asyncId, type, triggerAsyncId, resource) {
if (type !== 'PROMISE') {
return;
}
asyncIds.push(asyncId);
triggerIds.push(triggerAsyncId);
},
});
ah.enable();
// Simplified version of Node.js util.promisify(setTimeout)
function sleep(timeout) {
const promise = new Promise(function(resolve, reject) {
try {
setTimeout((err, ...values) => {
if (err) {
reject(err);
} else {
resolve(values[0]);
}
}, timeout);
} catch (err) {
reject(err);
}
});
return promise;
}
// Here goes the actual async code
async function foo() {
// await sleep(10);
// await something or create a promise
}
foo().then(() => {
let parsed = idsParse(asyncIds, triggerIds);
drawAsyncTree(parsed);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment