📄 debug.js
字号:
/*
* Isomorphic SmartClient
* Version 6.5 (2008-04-30)
* Copyright(c) 1998-2007 Isomorphic Software, Inc. All rights reserved.
* "SmartClient" is a trademark of Isomorphic Software, Inc.
*
* licensing@smartclient.com
*
* http://smartclient.com/license
*/
isc._debugMethods = { // Stack Traces // -------------------------------------------------------------------------------------------- // given the 'arguments' object from a function invocation, return a developer-readable summary, // complete with the names and values of the arguments //> @method Log.getCallTrace() // Returns a one-line summary of the current method call, showing method name and passed // arguments. // // @param [args] (Arguments) arguments object from the call to trace. On IE, defaults to the // calling function's arguments // // @group debug // @platformNotes IE only. // @visibility external //< getCallTrace : function (args, thisValue, showShortMethodBody) { if (args == null) args = arguments.caller; if (args == null) return "[getCallTrace(): Error: couldn't get arguments object]"; var output, func = args.callee; // determine function name from arguments.callee. arguments.callee property is the Function // instance being invoked. if (func == null) { // browser doesn't support args.callee? (should never happen) output = "[args.callee == null]"; } else if (!isc.Func) { output = "[Func utility class not loaded]"; } else { output = isc.Func.getName(func, true); } // output a summary of the parameters output += "("; // get the names of the parameters if available var argNames = (func != null ? isc.Func.getArgs(func) : []); // iterate to the larger of the declared parameters or the passed parameters var length = Math.max(args.length, argNames.length); for (var i = 0; i < length; i++) { var argName = argNames[i], argValue = args[i]; if (i > 0) output += ", "; if (argName != null) { // show the names of the parameters as eg // ListGrid.setRecordStyle(recordNum=>2, newStyle=>"cellDark"); // Note that there may be no name for the parameter if a parameter was passed // where none was expected. output += argName + "=>"; } output += this.echoLeaf(argValue); } output += ")"; // there's no known way to generally derive the value of "this" from the arguments object - // but in ISC several key methods store it explicitly. This is tremendously valuable in // trying to interpret long stacks with method calls weaving through several related // instances.a thisValue = thisValue || args.__this; if (thisValue) output += " on " + this.echoLeaf(thisValue); if (!showShortMethodBody && !func._showBodyInTrace) return output; var body = this._getTrimmedMethodBody(func); if (!func._showBodyInTrace) { // if the function at the top of the stack (the one that crashed) or at the // bottom of the stack (the entry point) is a one-liner, show it's contents. // This is very useful when an anoynmous expression is being called on a timer. // NOTE: have to be careful here to avoid spitting out giant methods: // - with stripping all functions in ISC are one-liners, hence the crude length // limit // - when using XML, very long functions are delivered as stringMethods // Could limit to anonymous functions like so: // && args.callee.getName && args.callee.getName() == "anonymous") var lines = body.split(/[\r\n]+/); if (lines.length > 1 || lines[0].length > 200) return output; } output += '\n "' + body + '"'; return output; }, // for when stack walking is enabled, trim off the try..catch block added to all functions _getTrimmedMethodBody : function (func) { var body = isc.Func.getBody(func); return body.trim(); }, //> @method Log.getStackTrace() // Returns a "stack trace" - one line per method in the current call stack, showing the method // name and any parameters passed. // <P> // This API can currently only be supported in Internet Explorer. See // +link{group:debugging} for information on how to get equivalent information from other // browsers. // // @return (String) stack trace. Use eg +link{Log.logWarn()} to log to the Developer // Console. // @group debug // @visibility external //< getStackTrace : function (args, ignoreLevels, maxLevels) { // Stack traces not supported on Safari as of 1.2 // - we have no way to get to the calling function or calling function's arguments object // as arguments.caller is undefined, as is arguments.callee.caller // Stack traces are not supported on Mozilla as of Moz 1.6 (Windows) // - arguments.caller is undefined, but arguments.callee.caller will give us a pointer // to the calling function, and arguments.callee.caller.arguments will give us a pointer // to the calling function's arguments object (equiv of arguments.caller in IE) // However we can't do stack traces if we have recursive calls, like this: // function f1() {f2()}; // function f2(continue) { if (!continue) return f2(true); f3()}; // function f3() {Log.logWarn(Log.getStackTrace());}; // The problem is that we can't get to f1 // - f3.arguments.callee.caller is f2 (arguments object is [true]) // - f3.arguments.callee.caller.caller is f2 // (arguments object is STILL [true] expected to be []) - so it's the same function, // in the same state as arguments.callee.caller // - f3.arguments.callee.caller.arguments.callee.caller is f2. // (arguments object is STILL [true]) - so this is another pointer to the same function // with the same arguments object. // - f3.argument.callee.caller.caller.caller is the same option - so you can keep // looking at the 'caller' property, and will get a pointer to the same function. // XXX: // We could catch this case, and return partial stack traces looking like this: // f3 () // f2 (a => true) // -- Recursive function call - unable to continue up stack // .. however the stack would quite frequently be cut very short due to Super(), // apply(), fireCallback() and other recurring functions that are not themselves // recursive. Not currently implemented. if (this.hasFireBug()) { isc.Log._fBugTrace = isc.Log._fBugTrace || 0; var traceId = "FBugTrace" + isc.Log._fBugTrace++; return this.fireBugTrace(traceId); } if (isc.Browser.isMoz || isc.Browser.isSafari) return " [Stack trace not supported in this browser]"; // if we are not passed a specific arguments function, default to the arguments object of // the function that asked for the stack trace if (args == null) args = arguments.caller; var output = []; // skip some of the stack (useful to eg, a logging subsystem) for (var i = 0; i < ignoreLevels; i++) { if (args.caller != null) args = args.caller; } var isIE7 = isc.Browser.isIE && isc.Browser.version > 6; var func = args.callee; var seenFuncs = []; var top = true; if (maxLevels == null) maxLevels = Number.MAX_VALUE; var numLevels = 0; while (func != null && args != null && numLevels < maxLevels) { if (isIE7) { if (seenFuncs.contains(func)) { output.add(" ** recursed on " + isc.Func.getName(func, true)); break; } seenFuncs.add(func); } output.add(" " + this.getCallTrace(args, null, (top || args.caller == null))); if (numLevels == 0) { var frameLocalsOutput = this._getFrameLocals(args.__frame); if (frameLocalsOutput) output.add(frameLocalsOutput); } func = args.callee; if (isIE7) { func = func.caller; if (func) args = func.arguments; } else args = args.caller; top = false; numLevels++; } if (output.length == 0) return ""; // skip a line at the beginning of the stack trace return "\r\n" + output.join("\r") + "\r"; }, hasFireBug : function () { return isc.Browser.isMoz && window.console != null && window.console.trace != null }, // this help function fireBugTrace : function (traceId) { window.console.trace(traceId); return " [Stack trace logged via Firebug: " + traceId + "]"; }, // get a report of local variable values from a frame (that is, a dump of local variable // values from the moment a function crashed) _getFrameLocals : function (frame) { var output = isc.SB.create(); for (var varName in frame) { var varValue = frame[varName], undef; // avoid reporting variables that have not yet been declared or assinged to. Note // this also catches values that have been explicitly assigned undef; we require // the developer to understand what the omission means. if (varValue === undef) continue; // ignore special values stored on the frame object (we assume no local variable // would be named with an _) if (isc.startsWith(varName, isc._underscore)) continue; output.append("\n " + varName + " = " + this.echoLeaf(varValue)); } return output.toString(); }, // called in two circumstances (split these uses?) // - when trapping JS errors at top level entry points (eg events) in non-IE browsers // - with "stackwalking" try..catch blocks added to all methods, called from every catch // block successively in order to walk the stack by catch..rethrow (any browser) _reportJSError : function (error, args, thisValue, frame) { // avoid reporting the same error twice if (error._reported) return; error._reported = true; var message = error.toString(); this.logWarn(message); }, // Echoing Objects // -------------------------------------------------------------------------------------------- //> @method Log.echoLeaf() // Return a very short (generally less than 40 characters) string representation of any object, // suitable for viewing by a developer for debugging purposes. // // @param obj (any) object to echo // @return (string) a short string representation of the object // // @group debug // @see echo() // @visibility external //< echoLeaf : function (obj, longMode) { var output = "", undefined; if (obj === undefined) return "undef"; try { if (isc.isA.Class(obj)) { // Always call toString() for instances of Classes. We need handle this case // specially, since typeof [instance of a Class] is "object", and we try to do // special things for vanilla Objects below output += obj.toString(); } else if (isc.isAn.Array(obj)) { output += "Array[" + obj.length + "]"; } else if (isc.isA.Date(obj)) { output += "Date(" + obj.toShortDate() + ")"; } else if (isc.isA.Function(obj)) { output += isc.Func.getName(obj, true) + "()"; } else { switch (typeof obj) { case "string" : // for shorter strings show the whole thing. Also, in "longMode" don't // shorten. if (obj.length <= 40 || longMode) { output += '"' + obj + '"'; break; } // for long strings, show an elipsis and the strings full length output += '"' + obj.substring(0, 40) + '..."[' + obj.length + ']'; // convert CR/LF to avoid spanning several lines output = output.replaceAll("\n", "\\n").replaceAll("\r", "\\r"); break; case "object" : // typeof null is "object" if (obj == null) { output += "null"; break; } // DOM object if (obj.tagName != null) { output += "[" + obj.tagName + "Element]" + this.getIDText(obj);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -