我找到了一种将状态信息(在这种情况下为 var .ua (Object))传递到递归函数的调用堆栈的方法;
代替
var fwa.animatedJavascriptControlCenter = {
...
,
scanElements : function (el, scanResult) {
// a function that walks the DOM tree to find elements that require molding by my js framework
if (!scanResult) scanResult={};
if (el.tagName.toLowerCase()!='svg') {
if (conditions_for_this_element_met(el)) {
scanResults[el.id] = el;
};
if (el.children.length>0) {
for (var i=0; i < el.children.length; i++) {
if (el.children[i].tagName.toUpperCase()!=='IFRAME') {
scanResult = fwa.animatedJavascriptControlCenter.scanElements(el.children[i], scanResult);
}
}
}
}
return scanResult;
},
...
}
做:
var fwa.animatedJavascriptControlCenter = {
...
,
scanElements : function (el, scanResult) {
if (!scanResult) scanResult={};
if (el.tagName.toLowerCase()!='svg') {
if (conditions_for_this_element_met(el)) {
scanResults[el.id] = el;
}
if (el.children.length>0) {
for (var i=0; i < el.children.length; i++) {
if (el.children[i].tagName.toUpperCase()!=='IFRAME') {
var args = [el.children[i], scanResult];
args.ua= tracer.findUA(arguments);
var passUAfunc = function(scanResult) {
return fwa.animatedJavascriptControlCenter.scanElements(el.children[i], scanResult);
}
passUAfunc.ua = args.ua;
scanResult = passUAfunc(scanResult);
}
}
}
}
return scanResult;
},
...
}
要完成这项工作,您还需要:
// Bonus : ;-)
// Enable the passage of the 'this' object through the JavaScript timers
// thanks to https://developer.mozilla.org/en/docs/DOM/window.setTimeout#Callback_arguments
var __nativeST__ = window.setTimeout, __nativeSI__ = window.setInterval;
window.setTimeout = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) {
var
oThis = this,
ua = tracer.findUA(arguments),
aArgs = Array.prototype.slice.call(arguments, 2);
if (ua) aArgs.ua = ua;
//if (!ua) debugger;
return __nativeST__(vCallback instanceof Function ? function () {
vCallback.apply(oThis, aArgs);
} : vCallback, nDelay);
};
window.setInterval = function (vCallback, nDelay /*, argumentToPass1, argumentToPass2, etc. */) {
var
oThis = this,
aArgs = Array.prototype.slice.call(arguments, 2),
ua = tracer.findUA(arguments);
if (ua) aArgs.ua = ua;
return __nativeSI__(vCallback instanceof Function ? function () {
vCallback.apply(oThis, aArgs);
} : vCallback, nDelay);
};
var tracer = {
/* object last modified : 14 May 2013, 04:46 CEST
original code by http://javascriptweblog.wordpress.com/2010/06/01/a-tracer-utility-in-2kb/
modified by rene7705@gmail.com with:
(1) http://stackoverflow.com/a/15582432/2379929
augmented by rene7705@gmail with (among other things):
http://stacktracejs.com/
this code is now used in and offered as part of the web-framework at http://fancywebapps.com
(component name : hipLog, to be released later)
*/
nativeCodeEx: /\[native code\]/,
tracing: [],
traced : [],
userActions : [],
findUA : function (arg) {
var p = arg;
if (p.ua) return p.ua;
var callee = arg.callee;
var caller = callee.caller;
var stack = [callee];
while (caller) {
if (stack.indexOf(caller) < 0) {
stack.push(caller);
args = caller.arguments;
callee = args.callee;
caller = callee.caller;
} else break;
}
while (p = stack.shift()) {
if (p.ua) return p.ua;
if (p.arguments && p.arguments.ua) return p.arguments.ua;
};
return false;
},
traceMe: function(func, methodName, path) {
var traceOn = function() {
var
ua = tracer.findUA(arguments),
startTime = +new Date;
if (!ua){
//debugger;
//ua = tracer.findUA(arguments);
};
//if (path=='fwa.animatedJavascriptControlCenter.scanElements') debugger;
if (!ua) {
//debugger;
var
uaIdx = tracer.userActions.length,
ua = tracer.userActions[uaIdx] = {
uaIdx : uaIdx,
startTime : startTime,
path : path,
stackLevel : 0
};
tracer.traced[uaIdx] = [];
} else {
var uaIdx = ua.uaIdx;
ua.stackLevel++;
}
arguments.ua = ua;
var idx = tracer.traced[uaIdx].length;
tracer.traced[uaIdx][idx] = {
path : path,
arguments : arguments
};
var result = func.apply(this, arguments);
tracer.traced[uaIdx][idx].stacktrace = printStackTrace() // see http://stacktracejs.com, free, quite useful
tracer.traced[uaIdx][idx].result = result;
tracer.traced[uaIdx][idx].timed = new Date - startTime;
tracer.traced[uaIdx][idx].stackLevel = ua.stackLevel;
ua.stackLevel--;
return result;
};
traceOn.traceOff = func;
for (var prop in func) {
traceOn[prop] = func[prop];
}
console.log("tracing " + path);
return traceOn;
},
traceAll: function(root, path, recurse) {
if ((root == window) || !((typeof root == 'object') || (typeof root == 'function'))) {return;}
for (var key in root) {
if ((root.hasOwnProperty(key)) && (root[key] != root)) {
var thisObj = root[key];
if (typeof thisObj == 'function') {
if ((this != root) && !thisObj.traceOff && !this.nativeCodeEx.test(thisObj)) {
root[key] = this.traceMe(root[key], key, path+'.'+key);
this.tracing.push({obj:root,methodName:key, path:path+'.'+key});
}
}
recurse && this.traceAll(thisObj, path+'.'+key, true);
}
}
},
untraceAll: function() {
for (var i=0; i<this.tracing.length; ++i) {
var thisTracing = this.tracing[i];
thisTracing.obj[thisTracing.methodName] =
thisTracing.obj[thisTracing.methodName].traceOff;
}
//console.log("tracing disabled");
tracer.tracing = [];
}
}
像这样使用:
// call this just after _completely_ defining yourFrameworkRootObject and yourSiteCodeRootObject
tracer.traceAll (yourFrameworkRootObject, true);
tracer.traceAll (yourSiteCodeRootObject, true);
仅供参考:此代码取自我的 js 框架http://fancywebapps.com,将成为它的 hipLog 组件的一部分,旨在向您展示完整的执行路径(有或没有往返服务器和/或 setTimeout( )s) 的任何 userAction,如点击、悬停或页面加载。