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

109

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

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

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

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

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

pasx
источник
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/

центурианский
источник
2
console.log(new Error);

Он покажет вам весь трек.

РатайС
источник
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