![](/img/trans.png)
[英]How to get javascript caller source line number in SpiderMonkey JSNative callback?
[英]How to get JavaScript caller function line number and caller source URL
我正在使用以下內容來獲取 JavaScript 調用函數名稱:
var callerFunc = arguments.callee.caller.toString();
callerFuncName = (callerFunc.substring(callerFunc.indexOf("function") + 8, callerFunc.indexOf("(")) || "anoynmous")
有沒有辦法發現調用方法的行號?
另外,有沒有辦法獲取調用該方法的 JavaScript 文件的名稱? 還是源網址?
這適用於我在chrome / QtWebView中
function getErrorObject(){
try { throw Error('') } catch(err) { return err; }
}
var err = getErrorObject();
var caller_line = err.stack.split("\n")[4];
var index = caller_line.indexOf("at ");
var clean = caller_line.slice(index+2, caller_line.length);
kangax的解決方案引入了不必要的try..catch范圍。 如果您需要訪問JavaScript中某行的行號(只要您使用的是Firefox或Opera),只需訪問(new Error).lineNumber
。
令我驚訝的是,大多數答案都假定您要處理錯誤,而不僅僅是在正常情況下也輸出有用的調試跟蹤。
例如,我喜歡這樣使用console.log
包裝器:
consoleLog = function(msg) {//See https://stackoverflow.com/a/27074218/470749
var e = new Error();
if (!e.stack)
try {
// IE requires the Error to actually be thrown or else the
// Error's 'stack' property is undefined.
throw e;
} catch (e) {
if (!e.stack) {
//return 0; // IE < 10, likely
}
}
var stack = e.stack.toString().split(/\r\n|\n/);
if (msg === '') {
msg = '""';
}
console.log(msg, ' [' + stack[1] + ']');
}
最終將輸出如下所示輸出到我的控制台:
1462567104174 [getAllPosts@http://me.com/helper.js:362:9]
請參閱https://stackoverflow.com/a/27074218/,以及具有正確行號的console.log的正確包裝?
這通常是通過從當前上下文拋出錯誤來實現的。 然后分析錯誤對象的屬性,如lineNumber
和fileName
(某些瀏覽器具有)
function getErrorObject(){
try { throw Error('') } catch(err) { return err; }
}
var err = getErrorObject();
err.fileName;
err.lineNumber; // or `err.line` in WebKit
不要忘記callee.caller
屬性已被棄用(首先在ECMA第三版中從來沒有真正使用過)。
行號實際上是靜態的,因此如果您只想將其用於記錄,則可以使用諸如gulp之類的東西對其進行預處理。 我寫了一個小gulp 插件 ,它確實做到了:
var gulp = require('gulp');
var logLine = require('gulp-log-line');
gulp.task('log-line', function() {
return gulp.src("file.js", {buffer : true})
//Write here the loggers you use.
.pipe(logLine(['console.log']))
.pipe(gulp.dest('./build'))
})
gulp.task('default', ['log-line'])
這會將文件名和行附加到console.log的所有日志中,因此console.log(something)
將成為console.log('filePath:fileNumber', something)
。 優點是,現在您可以合並文件,進行文件轉換了……您仍然可以
看來我有點晚了:),但是討論非常有趣,所以..到這里去了...假設您要構建一個錯誤處理程序,並且正在使用自己的異常處理程序類,例如:
function errorHandler(error){
this.errorMessage = error;
}
errorHandler.prototype. displayErrors = function(){
throw new Error(this.errorMessage);
}
您正在像這樣包裝代碼:
try{
if(condition){
//whatever...
}else{
throw new errorHandler('Some Error Message');
}
}catch(e){
e.displayErrors();
}
您很可能在單獨的.js文件中具有錯誤處理程序。
您會注意到,在firefox或chrome的錯誤控制台中,顯示的代碼行號(和文件名)是拋出“ Error”異常而不是您真正想要進行調試的“ errorHandler”異常的行(文件)簡單。 拋出自己的異常很好,但是在大型項目中,定位異常可能是一個大問題,尤其是在它們具有類似消息的情況下。 因此,您可以做的是將對實際的空Error對象的引用傳遞給錯誤處理程序,該引用將保存您想要的所有信息(例如,在firefox中,您可以獲取文件名和行號等。 ;在chrome中,如果您讀取Error實例的'stack'屬性,則會得到類似的結果。 長話短說,您可以執行以下操作:
function errorHandler(error, errorInstance){
this.errorMessage = error;
this. errorInstance = errorInstance;
}
errorHandler.prototype. displayErrors = function(){
//add the empty error trace to your message
this.errorMessage += ' stack trace: '+ this. errorInstance.stack;
throw new Error(this.errorMessage);
}
try{
if(condition){
//whatever...
}else{
throw new errorHandler('Some Error Message', new Error());
}
}catch(e){
e.displayErrors();
}
現在,您可以獲取引發自定義異常的實際文件和行號。
如果您想知道行號用於調試目的,或者僅在開發過程中(出於某種原因),則可以使用Firebug (Firefox擴展)並拋出異常。
編輯 :
如果出於某種原因確實需要在生產中執行此操作,則可以預處理javascript文件,以使每個函數都能跟蹤它所在的行。 我知道一些發現代碼覆蓋范圍的框架都使用此框架(例如JSCoverage )。
例如,假設您的原始通話為:
function x() {
1 + 1;
2 + 2;
y();
}
您可以編寫一個預處理器使其成為:
function x() {
var me = arguments.callee;
me.line = 1;
1 + 1;
me.line = 2;
2 + 2;
me.line = 3;
y();
}
然后在y()
,您可以使用arguments.callee.caller.line
來知道調用它的行,例如:
function y() {
alert(arguments.callee.caller.line);
}
我意識到這是一個老問題,但是現在有一個名為console.trace("Message")
,它將向您顯示行號和導致日志的方法調用鏈以及您傳遞的消息。 有關javascript記錄技巧的更多信息,請參見freecodecamp和此中等博客文章。
以下代碼在Mozilla和Chrome中對我有效。
它的日志功能顯示文件名和調用方所在的行。
log: function (arg) {
var toPrint = [];
for (var i = 0; i < arguments.length; ++i) {
toPrint.push(arguments[i]);
}
function getErrorObject(){
try { throw Error('') } catch(err) { return err; }
}
var err = getErrorObject(),
caller;
if ($.browser.mozilla) {
caller = err.stack.split("\n")[2];
} else {
caller = err.stack.split("\n")[4];
}
var index = caller.indexOf('.js');
var str = caller.substr(0, index + 3);
index = str.lastIndexOf('/');
str = str.substr(index + 1, str.length);
var info = "\t\tFile: " + str;
if ($.browser.mozilla) {
str = caller;
} else {
index = caller.lastIndexOf(':');
str = caller.substr(0, index);
}
index = str.lastIndexOf(':');
str = str.substr(index + 1, str.length);
info += " Line: " + str;
toPrint.push(info);
console.log.apply(console, toPrint);
}
我對JavaScript中的自定義錯誤的貢獻:
首先,我同意“ 從錯誤對象繼承”中的 @BT家伙-消息屬性在哪里? ,我們必須正確構建它(實際上,您必須使用js對象庫,我最喜歡的是: https : //github.com/jiem/my-class ):
window.g3 = window.g3 || {}; g3.Error = function (message, name, original) { this.original = original; this.name = name || 'Error.g3'; this.message = message || 'A g3.Error was thrown!'; (original)? this.stack = this.original.stack: this.stack = null; this.message += '<br>---STACK---<br>' + this.stack; }; var ClassEmpty = function() {}; ClassEmpty.prototype = Error.prototype; g3.Error.prototype = new ClassEmpty(); g3.Error.prototype.constructor = g3.Error;
然后,我們應該定義一個全局錯誤處理函數(可選),否則它們將最終到達引擎:
window.onerror = printError; function printError(msg, url, line){ document.getElementById('test').innerHTML = msg+'<br>at: '+url+'<br>line: '+line; return true; }
最后,我們應該仔細拋出自定義錯誤:
//hit it! //throw new g3.Error('Hey, this is an error message!', 'Error.Factory.g3'); throw new g3.Error('Hey, this is an error message!', 'Error.Factory.g3', new Error());
只有當將第三個參數作為new Error()
傳遞時,我們才能看到帶有函數和行號的堆棧!
在2,該函數還可以處理引擎引發的錯誤。
當然,真正的問題是我們是否真的需要它以及何時使用。 在某些情況下(我認為99%),正常返回false
就足夠了,並且僅留下一些關鍵點才能顯示,並拋出錯誤。
我就是這樣做的,我已經在Firefox和Chrome中對其進行了測試。 這樣就可以檢查調用函數的地方的文件名和行號。
logFileAndLineNumber(new Error());
function logFileAndLineNumber(newErr)
{
if(navigator.userAgent.indexOf("Firefox") != -1)
{
var originPath = newErr.stack.split('\n')[0].split("/");
var fileNameAndLineNumber = originPath[originPath.length - 1].split(">")[0];
console.log(fileNameAndLineNumber);
}else if(navigator.userAgent.indexOf("Chrome") != -1)
{
var originFile = newErr.stack.split('\n')[1].split('/');
var fileName = originFile[originFile.length - 1].split(':')[0];
var lineNumber = originFile[originFile.length - 1].split(':')[1];
console.log(fileName+" line "+lineNumber);
}
}
這是我根據此論壇上的信息寫的:
這是MyDebugNamespace的一部分,顯然Debug是保留的,不會用作名稱空間名稱。
var DEBUG = true;
...
if (true == DEBUG && !test)
{
var sAlert = "Assertion failed! ";
if (null != message)
sAlert += "\n" + message;
if (null != err)
sAlert += "\n" + "File: " + err.fileName + "\n" + "Line: " + err.lineNumber;
alert(sAlert);
}
...
通話方式:
MyDebugNamespace.Assert(new Error(""), (null != someVar), "Something is wrong!")
我在名稱空間中包括了兩個函數,它們具有可變數量的參數來調用此基本代碼,以便有選擇地忽略消息或調用錯誤。
這在Firefox,IE6和Chrome上正常工作,將fileName和lineNumber報告為undefined。
過去更容易,但此時瀏覽器更新:
這是安全的多瀏覽器解決方案
<!DOCTYPE html>
<html lang="en">
<head>
<script>
var lastErr;
function errHand(e) {
lastErr = e;
switch (e.target.nodeName) {
case 'SCRIPT':
alert('script not found: ' + e.srcElement.src);
break;
case 'LINK':
alert('css not found: ' + e.srcElement.href);
}
return false;
}
window.onerror = function (msg, url, lineNo, columnNo, error) {
alert(msg + ' - ' + url + ' - ' + lineNo + ' - ' + columnNo);
return false;
}
</script>
<script src="http://22.com/k.js" onerror="errHand(event)"></script>
<link rel="stylesheet" href="http://22.com/k.css" onerror="errHand(event)" type="text/css" />
</head>
<body>
<script>
not_exist_function();
</script>
</body>
</html>
對於 NodeJS - 全局錯誤處理解決方案
process.on('uncaughtException', function (err) {
console.error('uncaughtException:\n' + err.stack + '\n');
})
這非常有用,因為它會向您顯示存在但不會破壞主程序進程的錯誤。
要確定某行在哪一行,您必須在所有代碼中搜索占據特定關注行的代碼,並從頂部開始到該關注行計算“ \\ n”字符,然后加1。
我實際上是在我正在編寫的應用程序中執行此操作。 它是HTML的最佳實踐驗證器,並且仍在大量開發中,但是您感興趣的錯誤輸出過程已經完成。
console.log(new Error);
它將向您顯示整個軌道。
如果您需要非常完整和准確的內容,對於 v8(即 NodeJS 和 Chrome),有stack-trace
包,它對我有用:
https://www.npmjs.com/package/stack-trace
這有幾個優點:能夠產生深度堆棧跟蹤,能夠遍歷async
調用,並在每個堆棧幀提供腳本的完整 URL。
您可以在此處找到有關 v8 堆棧跟蹤 API 的更多信息。
如果您需要在更多瀏覽器中工作的東西,有這個包:
https://www.npmjs.com/package/stacktrace-js
該庫解析您通常在 devtools 控制台中看到的格式化堆棧跟蹤字符串,這意味着它只能訪問實際出現在格式化堆棧跟蹤中的信息 - 與 v8 API 不同,您無法獲得(除其他外)堆棧幀中腳本的完整 URL。
請注意,解析格式化的堆棧跟蹤是一種有點脆弱的方法,因為這種格式可能會在瀏覽器中發生變化,這會破壞您的應用程序。
據我所知,對於跨瀏覽器的東西沒有更安全的選擇——如果你需要一些在所有瀏覽器中都能運行的快速、准確和完整的東西,那么你就很不走運了。
答案很簡單。 不,不(不)。
到javascript運行時,源文件/ URL的概念就消失了。
也沒有辦法確定行號,因為再次在執行時,代碼“行”的概念在Javascript中不再有意義。
特定的實現可以提供API掛鈎,以允許特權代碼訪問此類詳細信息以進行調試,但是這些API不會暴露給普通的標准Javascript代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.