Як отримати номер рядка функції виклику 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 [фіксована посилання]
Scotts

Відповіді:


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 вводить непотрібну область спробу. Якщо вам потрібно отримати доступ до номера рядка чогось у JavaScript (доки ви користуєтеся Firefox або Opera), просто перейдіть (new Error).lineNumber.


11
Привіт, спасибі за цей аддон. чи знаєте ви, чи можливо отримати номер лінії від попереднього дзвінка? Скажімо, метод A викликає B, і тепер у BI хотілося б знати, у якому рядку під A був здійснений виклик?
Тал

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 властивість застаріла (і в першу чергу ніколи не була в третьому виданні ECMA).

Також пам’ятайте, що декомпіляція функції визначена як залежна від реалізації, і тому може дати досить несподівані результати. Я писав про це тут і тут .


Дякую, здається, трохи проблематично додати цей код у потрібну мені програму. (деякі рамки відстеження js) Чи знаєте ви будь-який інший метод, який не застарілий, який я можу використовувати?
Тал

Ви повинні мати можливість перевірити об'єкт помилки, не покладаючись на застарілий callee.caller.
кенгакс

Помилку не потрібно кидати. Ви просто використовуєте (нова помилка) .lineNumber для доступу до поточного номера рядка в сценарії.
Елі Грей

@Elijah Це я бачу у FF3. З іншого боку, WebKit заповнюється lineлише при помилці.
кенгакс

Що таке заміна callee.caller? Якщо мені потрібно отримати ім'я функції?
Тал

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
Дякую, я хотів би цього у виробництві з міркувань підтримки. Я знайшов якийсь код, який дозволяє вам бачити стек викликів всього потоку, поки метод не має, але у нього немає номерів рядків, куди були названі методи. Я думаю, що для цього просте рішення?
Тал

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, налагодження, очевидно, зарезервоване і не виконуватиметься як ім'я простору імен.

    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, повідомляють про ім’я файлу та рядокNumber як невизначені.


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 у " Успадкуванні" від об'єкта "Помилка" - де властивість повідомлення? , ми мусимо її правильно побудувати (власне, ви повинні використовувати бібліотеку об'єктів 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


конкретна лінія інтересу може бути багатьма ... Якщо у мене є той самий метод, який викликався кілька разів від іншого методу, то як я можу знати (у тому іншому методі) звідки прийшов виклик?
Тал

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

-2

Відповіді прості. Ні і ні (ні).

До того часу, як у JavaScript працює концепція вихідних файлів / URL-адрес, з яких пішов прихід.

Також немає способу визначити номер рядка, оскільки з моменту виконання поняття коду "рядки" вже не має сенсу в JavaScript.

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


У Firefox винятки включають таку інформацію ... чи можливо це було б принаймні у firefox?
Зойдберг

Коли ви запускаєте налагоджувач MS Script і ставите деяку точку перелому, у стеку викликів ви бачите, де саме ви прийшли. Це через спеціалізовані гачки?
Тал

"знову ж таки до моменту виконання, поняття коду" рядки "вже не має значення в JavaScript." Так? JS вже показує номер рядка щоразу, коли ви запускаєте console.log ()
mikemaccana

@AnthonyWJones Так. Це чітко суперечить дещо абсолютному "Ні і Ні (Ні)".
mikemaccana

@nailer: Ще в 2009 році в усіх основних веб-переглядачах, яким чином суперечить моя відповідь. Майте на увазі, питання, яке стосується того, чи є відкриття в JavaScript, що знаходиться в рядку номера виклику?
AnthonyWJones
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.