Created
December 2, 2009 20:09
-
-
Save pmuellr/247514 to your computer and use it in GitHub Desktop.
JavaScript traceback sample
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// sample code | |
function legend(message) { | |
var dashes = new Array(60).join("-") | |
console.log(dashes) | |
console.log(message) | |
console.log(dashes) | |
console.log("") | |
} | |
// tests with user-land function | |
function factorial(n) { | |
if (n <= 0) return 1 | |
return n * factorial(n-1) | |
} | |
function printFactorial(n) { | |
console.log(n + "! == " + factorial(n)) | |
console.log("") | |
} | |
function a() { b() } | |
function b() { c() } | |
function c() { | |
printFactorial(0) | |
printFactorial(5) | |
} | |
legend("calling factorial() before wrapping") | |
a() | |
factorial = wrapWithBackTrace(factorial) | |
legend("calling factorial() after wrapping") | |
a() | |
legend("calling factorial() at top level") | |
factorial(0) | |
// tests with built-in function | |
setTimeout = wrapWithBackTrace(setTimeout) | |
function doNothing() { | |
console.log("in doNothing()") | |
console.log("") | |
} | |
function x() { y() } | |
function y() { z() } | |
function z() { setTimeout(doNothing, 100) } | |
legend("calling setTimeout() after wrapping") | |
x() | |
legend("calling setTimeout() at top level") | |
setTimeout(doNothing, 200) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// requires Array.indexOf, Array.map, and Array.forEach | |
// if you don't have these, you can get portable implementations here: | |
// https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/Array | |
//--------------------------------------------------------------------- | |
// wrap a function with a backtrace printer | |
// | |
// parameters: | |
// func: the function to wrap | |
// receiver: the (optional) receiver to call func with | |
// | |
// returns: | |
// a new function to use in replace of the original function | |
//--------------------------------------------------------------------- | |
function wrapWithBackTrace(func, receiver) { | |
// get the name of a function | |
function funcName(func) { | |
return func.name || "{anonymous}" | |
} | |
// generate the actual backtrace as an array of strings | |
function getBackTrace() { | |
var stack = [] | |
var func = arguments.callee.caller.caller | |
// iterate through the stack | |
while (func) { | |
// check for recursion! | |
if (stack.indexOf(func) != -1) { | |
stack.push({name: "... recursion on " + funcName(func)}) | |
break | |
} | |
// collect results, move to next entry | |
stack.push(func) | |
func = func.caller | |
} | |
// convert results to function names | |
var result = stack.map(function(element) { | |
return funcName(element) + "()" | |
}) | |
// if nothing on stack, was a top level call | |
if (!result.length) result = ["{top level call}"] | |
return result | |
} | |
// returns the function to use as a replacement | |
return function wrappedWithBackTrace() { | |
// get the calling arguments | |
var args = Array.prototype.slice.call(arguments) | |
// call the original function | |
var result = func.apply(receiver, args) | |
// get the back trace | |
var trace = getBackTrace() | |
// get our function name | |
var name = funcName(func) | |
// print results | |
console.log("backtrace for " + name + "()") | |
trace.forEach(function (element) { | |
console.log(" - " + element) | |
}) | |
console.log("") | |
return result | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment