簡體   English   中英

如何獲取 JavaScript 調用者函數行號和調用者源 URL

[英]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的正確包裝?

這通常是通過從當前上下文拋出錯誤來實現的。 然后分析錯誤對象的屬性,如lineNumberfileName (某些瀏覽器具有)

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中的自定義錯誤的貢獻:

  1. 首先,我同意“ 從錯誤對象繼承”中的 @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; 
  2. 然后,我們應該定義一個全局錯誤處理函數(可選),否則它們將最終到達引擎:

     window.onerror = printError; function printError(msg, url, line){ document.getElementById('test').innerHTML = msg+'<br>at: '+url+'<br>line: '+line; return true; } 
  3. 最后,我們應該仔細拋出自定義錯誤:

     //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就足夠了,並且僅留下一些關鍵點才能顯示,並拋出錯誤。

示例: http//jsfiddle.net/centurianii/m2sQ3/1/

我就是這樣做的,我已經在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>
  1. 不要嘗試通過瀏覽器覆蓋或讀取控制台自動生成的錯誤日志,此時不起作用,但過去發生過
  2. 為了控制加載每個外部鏈接的 css/js/etc 使用onerror事件屬性innertag
  3. 對於控制內聯/加載的腳本,請使用window.onerror
  4. 將錯誤處理函數放在 html 代碼的頂部
  5. 要為其他特殊標簽(如“include”)開發此代碼,請設置onerror內聯事件(如步驟 2)和發生火災后的錯誤,請使用console.log(lastErr)查看錯誤對象字段
  6. 如果附加js文件的來源有錯誤,那么window.onerror會在js與主html文件具有同源主機時獲取完整日志,如果您在沒有主機的本地測試這種情況,則日志完整因為本地無主機環境不知道是同源的
  7. 對於像Ajax / Websocket這樣的發送請求錯誤處理,最好使用它們的內置錯誤處理函數

對於 NodeJS - 全局錯誤處理解決方案

process.on('uncaughtException', function (err) {
    console.error('uncaughtException:\n' + err.stack + '\n');
})

非常有用,因為它會向您顯示存在但不會破壞主程序進程的錯誤。

要確定某行在哪一行,您必須在所有代碼中搜索占據特定關注行的代碼,並從頂部開始到該關注行計算“ \\ n”字符,然后加1。

我實際上是在我正在編寫的應用程序中執行此操作。 它是HTML的最佳實踐驗證器,並且仍在大量開發中,但是您感興趣的錯誤輸出過程已經完成。

http://mailmarkup.org/htmlint/htmlint.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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM