Как получить номер строки функции вызывающего абонента JavaScript? Как получить URL-адрес источника вызывающего абонента JavaScript?


109

Я использую следующее для получения имени функции вызывающего абонента JavaScript:

var callerFunc = arguments.callee.caller.toString();
callerFuncName = (callerFunc.substring(callerFunc.indexOf("function") + 8, callerFunc.indexOf("(")) || "anoynmous")

Есть ли способ узнать номер строки, из которой был вызван метод?

Кроме того, есть ли способ получить имя файла JavaScript, из которого был вызван метод? Или исходный URL?


2
Я не думаю, что это возможно в IE, иначе у нас был бы способ обойти там CRAPPY сообщения об ошибках, которые не содержат деталей. Но если это возможно, я тоже хотел бы знать!
Зойдберг,

Да. Вот кроссбраузерная функция, которая использует проприетарные методы каждого браузера: github.com/eriwen/javascript-stacktrace [фиксированная ссылка]
Скоттс,

Ответы:


99

Это работает для меня в 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);

Также работает в узле. Поместите это в свою пользовательскую функцию log () (которая добавляет любые другие полезные обходные пути, которые вам нужны - например, исправлено для ведения журнала массива Chrome) и по-прежнему номера строк из того места, где вы вызывали log ().
mikemaccana

60
Не нужно выдавать ошибку; просто создать его достаточно:var caller_line = (new Error).stack.split("\n")[4]
ELLIOTTCABLE

2
Объединенное это предложение с другим подобным ответом чтобы получить FF / Webkit «стандартизированы» ответ - см stackoverflow.com/a/14841411/1037948
drzaus

1
Работает и в PhantomJS, но вы должны его выбросить, иначе атрибут "stack" не установлен для ошибки.
Джошуа Ричардсон

1
@ELLIOTTCABLE на самом деле в некоторых браузерах, таких как iOS safari, вам нужно выбросить исключение! Так почему бы не сделать это?
arctelix

26

Решение kangax вводит ненужную область видимости try..catch. Если вам нужно получить доступ к номеру строки чего-либо в JavaScript (если вы используете Firefox или Opera), просто откройте (new Error).lineNumber.


11
Привет, спасибо за это дополнение. знаете ли вы, можно ли узнать номер линии из предыдущего звонка? Допустим, метод A вызывает B, а теперь в BI хотелось бы знать, в какой строке под A был сделан вызов?
Tal

85
Он отмечен галочкой, но не отвечает на вопрос, как получить номер строки функции вызывающего абонента .
mikemaccana

3
Кроме того, это крайне ограничено. Лучшее решение - выдать ошибку и использовать регулярное выражение в error.stack, которое доступно во всех современных браузерах. Вы можете легко извлечь этот путь, файл, строку и столбец. Нет проблем.
arctelix

13

Я был удивлен, что в большинстве этих ответов предполагалось, что вы хотите обработать ошибку, а не просто выводить полезные трассировки отладки для обычных случаев.

Например, мне нравится использовать такую 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 с правильным номером строки?


1
работает для браузера firefox, но не работает для node.js.
молния

1
под узлом вы должны
записать

5

Это часто достигается путем выдачи ошибки из текущего контекста; затем анализируя объект ошибки для таких свойств, как 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свойство устарело (и никогда не упоминалось в 3-м издании ECMA).

Также помните, что декомпиляция функции зависит от реализации и может привести к весьма неожиданным результатам. Я писал об этом здесь и здесь .


Спасибо, добавить этот код в нужное мне приложение проблематично. (некоторые рамки трассировки js) Знаете ли вы какой-либо другой метод, который не является устаревшим, который я могу использовать?
Tal

Вы должны иметь возможность проверять объект ошибки, не полагаясь на устаревший callee.caller.
kangax

Вам не нужно бросать ошибку. Вы просто используете (новая ошибка) .lineNumber для доступа к текущему номеру строки в скрипте.
Эли Грей

@Elijah Вот что я вижу в FF3. WebKit, с другой стороны, заполняется lineтолько при возникновении ошибки.
kangax

Что является заменой для callee.caller? Если мне нужно получить имя функции?
Tal

4

Кажется, я немного опоздал :), но обсуждение довольно интересное, так что ... вот оно ... Предполагая, что вы хотите создать обработчик ошибок, и вы используете свой собственный класс обработчика исключений, например:

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 показанный номер строки кода (и имя файла) - это строка (файл), которая выдает исключение «Ошибка», а не исключение «errorHandler», которое вы действительно хотите для выполнения отладки. легко. Создание собственных исключений - это здорово, но в крупных проектах их обнаружение может быть серьезной проблемой, особенно если у них есть похожие сообщения. Итак, что вы можете сделать, так это передать ссылку на фактический пустой объект Error вашему обработчику ошибок, и эта ссылка будет содержать всю необходимую информацию (например, в firefox вы можете получить имя файла, номер строки и т. Д. ; в chrome вы получите нечто подобное, если прочитаете свойство 'stack' экземпляра Error). Короче говоря, вы можете сделать что-то вроде этого:

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();
}

Теперь вы можете получить фактический файл и номер строки, в которой возникло пользовательское исключение.


4

Номер строки на самом деле является чем-то статическим, поэтому, если вы просто хотите, чтобы он был записан, его можно предварительно обработать чем-то вроде 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). Преимущество состоит в том, что теперь вы можете объединять свои файлы, переносить их ... и вы все равно получите строку


Это кажется отличным предложением для ситуаций, когда используется транспилятор (например, при использовании TypeScript). Спасибо!
Энди Кинг

4

Я понимаю, что это старый вопрос, но теперь есть метод, называемый console.trace("Message") , который покажет вам номер строки и цепочку вызовов методов, которые привели к журналу, вместе с сообщением, которое вы ему передали. Дополнительная информация о трюках с журналированием javascript доступна здесь, на freecodecamp и в этом среднем сообщении в блоге.


3

Если вы хотите знать номер строки для целей отладки или только во время разработки (по какой-либо причине), вы можете использовать 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);
}

1
Спасибо, я хотел бы, чтобы это было в рабочей среде по причинам поддержки. Я нашел код, который позволяет вам видеть стек вызовов всего потока до метода, но в нем нет номеров строк, в которых были вызваны методы. Думаю, какое простое решение для этого?
Tal

3

Вот как я это сделал, я тестировал и в 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);
    }
}

2

Вот что я написал на основе информации, найденной на этом форуме:

Это часть 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 сообщают, что имя файла и номер строки не определены.


2

следующий код работает у меня в 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);
}

Похоже, чего-то не хватает. Я получаю:SyntaxError: function statement requires a name,log: function (arg) {
spiderplant0

Мне нравится эта идея, но номера строк получаются неверными.
Райан

2

Мой вклад в пользовательские ошибки в JavaScript:

  1. Во-первых, я согласен с этим парнем из @BT в наследовании от объекта Error - где свойство сообщения? , мы должны построить его правильно (на самом деле вам нужно использовать библиотеку объектов 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/



1

Чтобы определить, в какой строке что-то находится, вам нужно найти во всем коде код, который занимает конкретную интересующую строку, и посчитать символы «\ n» сверху до нужной и добавить 1.

Я действительно делаю это в приложении, которое пишу. Это валидатор передовых практик для HTML, который все еще находится в стадии разработки, но процесс вывода ошибок, который вас может заинтересовать, завершен.

http://mailmarkup.org/htmlint/htmlint.html


конкретной интересующей линии может быть много ... Если у меня один и тот же метод вызывается несколько раз из другого метода, как я могу узнать (в этом другом методе), откуда пришел вызов?
Tal

Вы не сможете анализировать интерпретацию JavaScript во время выполнения извне интерпретатора. Вы можете написать программу для отслеживания пути выполнения в вашей программе, но это будет именно эта программа, а не код, который вы хотите анализировать. Обычно это сложная задача, которая выполняется вручную с помощью инструментов. Если вы действительно хотите увидеть, что происходит в вашем коде во время его выполнения, пусть он записывает на экран метаданные, которые сообщают, что вы хотите, чтобы решения выполнялись, какие другие части выполняются.

-2

Ответы просты. Нет и нет (нет).

К тому времени, когда javascript запустит концепцию исходных файлов / URL-адресов, исходные файлы исчезли.

Также нет способа определить номер строки, потому что снова к моменту выполнения понятие «строки» кода больше не имеет смысла в Javascript.

Конкретные реализации могут предоставлять перехватчики API, позволяющие привилегированному коду получить доступ к таким деталям с целью отладки, но эти API не доступны для обычного стандартного кода Javascript.


В firefox исключения включают такую ​​информацию ... возможно ли это хотя бы в firefox?
Зойдберг,

Когда вы запускаете отладчик MS Script и устанавливаете точку останова, вы видите в стеке вызовов, откуда именно вы пришли. Это из-за специализированных хуков?
Tal

«опять же, к моменту выполнения понятие« строки »кода больше не имеет смысла в Javascript». А? JS уже показывает номер строки каждый раз, когда вы запускаете console.log ()
mikemaccana

@AnthonyWJones Да. Это явно противоречит несколько абсолютному «Нет и Нет (Нет)».
mikemaccana

@nailer: Еще в 2009 году во всех основных браузерах мой ответ противоречил. Имейте в виду, что данный вопрос касается обнаружения при запуске javascript номера строки вызываемого абонента?
AnthonyWJones
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.