Skip to content

Instantly share code, notes, and snippets.

@wentout
Last active November 8, 2018 19:58
Show Gist options
  • Save wentout/263f7e73ba4f14c1a125b40a1aafa8a0 to your computer and use it in GitHub Desktop.
Save wentout/263f7e73ba4f14c1a125b40a1aafa8a0 to your computer and use it in GitHub Desktop.
CLS implementation using wrapped function. Polling problem shown from line 111.
'use strict';
// HOOKS EXAMPLE START
var counter = 0;
var currentId = 0;
var hooks = {
init: [],
before: [],
after: [],
// unable to implement real destroy
// cause no access to GC
destroy: []
};
// we wouldn't implement hookClearTimeout,
// cause it long for just an example
// in real life same code wraps setTimeout in node!!!
var hookSetTimeoout = function (cb, t, ...params) {
counter++;
hooks.init.forEach(function (hook) {
hook(counter, currentId, cb);
});
var runWrapper = function (hook) {
var destroyId = currentId;
hooks.destroy.forEach(function (hook) {
// need to skip one else frame
// before deleting
setTimeout(function () {
hook(this); // previous currentId
}.bind(destroyId), 0);
});
currentId = this;
hooks.before.forEach(function (hook) {
hook(currentId);
});
cb.call(null, ...params);
hooks.after.forEach(function (hook) {
hook(currentId);
});
}.bind(counter);
setTimeout(runWrapper, t);
};
// HOOKS EXAMPLE STOP
// [C|T]LS EXAMPLE START
var contexts = {};
var currentContext;
hooks.init.push(function (asyncId, triggerId) {
if (currentContext) {
// context start from wrapped function
contexts[asyncId] = currentContext;
return;
}
contexts[asyncId] = contexts[triggerId];
});
hooks.before.push(function (asyncId) {
currentContext = contexts[asyncId];
});
hooks.after.push(function () {
currentContext = undefined;
});
hooks.destroy.push(function (asyncId) {
// delete contexts[asyncId];
});
// won't implement stop tracing!
var cls = {
getData() {
return currentContext;
},
setData(data, cb) {
currentContext = data;
cb();
currentContext = undefined;;
}
};
// [C|T] EXAMPLE STOP
// WORKING EXAMPLE CODE START
cls.setData('test', function () {
console.log('0', cls.getData());
hookSetTimeoout(function () {
console.log('1', cls.getData());
}, 100);
});
// WORKING EXAMPLE CODE STOP
var pollingTasks = [];
var pollingRunner = function () {
pollingTasks.forEach(function (task) {
task();
});
pollingTasks = [];
hookSetTimeoout(pollingRunner, 100);
};
hookSetTimeoout(pollingRunner, 100);
pollingTasks.push(function () {
console.log('! must be undefined : ', cls.getData());
});
cls.setData('failure test', function () {
console.log('! exists, good : ', cls.getData());
pollingTasks.push(function () {
console.log('! will be undefined, WRONG : ', cls.getData());
});
});
'use strict';
// HOOKS EXAMPLE START
var counter = 0;
var currentId = 0;
var hooks = {
init: [],
before: [],
after: [],
// unable to implement real destroy
// cause no access to GC
destroy: []
};
// we wouldn't implement hookClearTimeout,
// cause it long for just an example
// in real life same code wraps setTimeout in node!!!
var hookSetTimeoout = function (cb, t, ...params) {
counter++;
hooks.init.forEach(function (hook) {
hook(counter, currentId, cb);
});
var runWrapper = function (hook) {
var destroyId = currentId;
hooks.destroy.forEach(function (hook) {
// need to skip one else frame
// before deleting
setTimeout(function () {
hook(this); // previous currentId
}.bind(destroyId), 0);
});
currentId = this;
hooks.before.forEach(function (hook) {
hook(currentId);
});
cb.call(null, ...params);
hooks.after.forEach(function (hook) {
hook(currentId);
});
}.bind(counter);
setTimeout(runWrapper, t);
};
// HOOKS EXAMPLE STOP
// [C|T]LS EXAMPLE START
// var context = {};
var context = new Map();
context.set(0, 'unreachable');
var stack = [0];
hooks.init.push(function (asyncId, triggerId) {
// context[asyncId] = context[triggerId];
context.set(asyncId, context.get(triggerId));
});
hooks.before.push(function (asyncId) {
stack.push(asyncId);
});
hooks.after.push(function () {
stack.pop();
});
hooks.destroy.push(function (asyncId) {
context.delete(asyncId);
// delete context[asyncId];
});
// won't implement stop tracing!
var cls = {
getData() {
// return context[stack.slice(-1)[0]];
return context.get(stack.slice(-1)[0]);
},
setData(data) {
// context[stack.slice(-1)[0]] = data;
context.set(stack.slice(-1)[0], data);
}
};
// [C|T] EXAMPLE STOP
// WORKING EXAMPLE CODE START
hookSetTimeoout(function () {
cls.setData('test');
hookSetTimeoout(function () {
console.log(cls.getData());
}, 100);
}, 100);
// WORKING EXAMPLE CODE STOP
var pollingTasks = [];
var pollingRunner = function () {
pollingTasks.forEach(function (task) {
task();
});
pollingTasks = [];
hookSetTimeoout(pollingRunner, 100);
};
hookSetTimeoout(pollingRunner, 100);
pollingTasks.push(function () {
console.log('must be unreachable > ', cls.getData());
});
// POLLING PROBLEM ITSELF
hookSetTimeoout(function () {
cls.setData('failure test');
console.log('POLLING PROBLEM ITSELF\n');
pollingTasks.push(function () {
console.log('wish to be present, but > ', cls.getData());
});
}, 1000);
@wentout
Copy link
Author

wentout commented Nov 8, 2018

simple demonstration of Async Hooks "under the hood".

Based on Idea itself, but not on real implementation!

Just to Show how it works

and where CLS failed 2 Polling Problem

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment