Bagaimana cara mendapatkan nomor baris fungsi pemanggil JavaScript? Bagaimana cara mendapatkan URL sumber pemanggil JavaScript?

109

Saya menggunakan yang berikut ini untuk mendapatkan nama fungsi pemanggil JavaScript:

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

Adakah cara untuk menemukan nomor baris dari mana metode itu dipanggil?

Juga, apakah ada cara untuk mendapatkan nama file JavaScript dari mana metode itu dipanggil? Atau URL sumbernya?

Tal
sumber
2
Saya tidak berpikir ini mungkin di IE, atau kami akan memiliki cara untuk berkeliling di sana pesan kesalahan CRAPPY yang tidak memberikan detail. Tetapi jika memungkinkan, saya ingin tahu juga!
Zoidberg
Iya. Berikut adalah fungsi lintas-browser yang menggunakan metode kepemilikan masing-masing browser: github.com/eriwen/javascript-stacktrace [tautan tetap]
scotts

Jawaban:

99

Ini berfungsi untuk saya di 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);
Nathan Landis
sumber
Bekerja di node juga. Masukkan ini ke dalam fungsi custom log () Anda (yang menambahkan solusi berguna lainnya yang Anda butuhkan - misalnya tetap untuk logging array Chrome) dan nomor baris diam dari mana pun Anda memanggil log ().
mikemaccana
60
Tidak perlu membuang kesalahan; hanya membuatnya sudah cukup:var caller_line = (new Error).stack.split("\n")[4]
ELLIOTTCABLE
2
Gabungkan saran ini dengan jawaban lain yang serupa untuk mendapatkan tanggapan "standar" FF / Webkit - lihat stackoverflow.com/a/14841411/1037948
drzaus
1
Bekerja di PhantomJS juga, tetapi Anda harus membuangnya, atau atribut "stack" tidak disetel pada kesalahan tersebut.
Joshua Richardson
1
@ELLIOTTCABLE sebenarnya di beberapa browser seperti Safari iOS, Anda perlu membuang pengecualian! Jadi kenapa tidak melakukannya?
arctelix
26

solusi kangax memperkenalkan lingkup coba..catch yang tidak perlu. Jika Anda perlu mengakses nomor baris sesuatu di JavaScript (selama Anda menggunakan Firefox atau Opera), cukup akses (new Error).lineNumber.

Eli Grey
sumber
11
Hai, Terima kasih untuk addon itu. apakah Anda tahu apakah mungkin untuk mendapatkan nomor baris dari panggilan sebelumnya? Katakanlah metode A memanggil B, dan sekarang di BI ingin tahu di baris mana di bawah A panggilan itu dilakukan?
Tal
85
Ini dicentang, tetapi tidak menjawab pertanyaan, yaitu bagaimana mendapatkan nomor baris dari fungsi pemanggil .
mikemaccana
3
Juga, ini sangat terbatas. Solusi terbaik adalah membuang kesalahan dan menggunakan regex di error.stack yang tersedia di semua browser modern. Anda dapat dengan mudah mengekstrak jalur, file, baris, dan kolom itu. Tidak masalah.
arctelix
13

Saya terkejut bahwa sebagian besar jawaban ini berasumsi bahwa Anda ingin menangani kesalahan daripada hanya menampilkan jejak debug yang bermanfaat untuk kasus normal juga.

Misalnya, saya suka menggunakan console.logpembungkus seperti ini:

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] + ']');        
}

Ini akhirnya mencetak output seperti berikut ke konsol saya:

1462567104174 [getAllPosts@http://me.com/helper.js:362:9]

Lihat https://stackoverflow.com/a/27074218/ dan juga Pembungkus yang tepat untuk console.log dengan nomor baris yang benar?

Ryan
sumber
1
berfungsi untuk browser firefox, tetapi tidak berfungsi untuk node.js.
ritsleting
1
di bawah node Anda harus mencatat tumpukan [2]
monika mevenkamp
5

Ini sering kali dicapai dengan melemparkan kesalahan dari konteks saat ini; kemudian menganalisis objek kesalahan untuk properti seperti lineNumberdan fileName(yang dimiliki beberapa browser)

function getErrorObject(){
  try { throw Error('') } catch(err) { return err; }
}

var err = getErrorObject();

err.fileName;
err.lineNumber; // or `err.line` in WebKit

Jangan lupa bahwa callee.callerproperti sudah usang (dan tidak pernah benar-benar ada di ECMA edisi ke-3 sejak awal).

Ingat juga bahwa dekompilasi fungsi ditetapkan sebagai ketergantungan implementasi sehingga mungkin menghasilkan hasil yang tidak terduga. Saya menulis tentang itu di sini dan di sini .

kangax
sumber
Terima kasih, sepertinya agak bermasalah untuk menambahkan kode ini di aplikasi yang saya butuhkan. (beberapa js tracing framework) Apakah Anda tahu metode lain yang tidak usang yang dapat saya gunakan?
Tal
Anda harus bisa memeriksa objek kesalahan tanpa bergantung pada deprecated callee.caller.
kangax
Anda tidak perlu membuang Error. Anda hanya menggunakan (Error baru] .lineNumber untuk mengakses nomor baris saat ini dalam skrip.
Eli Gray
@Elijah Itulah yang saya lihat di FF3. WebKit, di sisi lain, linehanya mengisi ketika kesalahan terjadi.
kangax
Apa pengganti callee.caller? Jika saya perlu mendapatkan nama fungsi?
Tal
4

Sepertinya saya agak terlambat :), tetapi pembahasannya cukup menarik jadi .. ini dia ... Dengan asumsi Anda ingin membuat penangan kesalahan, dan Anda menggunakan kelas penangan pengecualian Anda sendiri seperti:

function  errorHandler(error){
    this.errorMessage = error;
}
errorHandler.prototype. displayErrors = function(){
    throw new Error(this.errorMessage);
}

Dan Anda membungkus kode Anda seperti ini:

try{
if(condition){
    //whatever...
}else{
    throw new errorHandler('Some Error Message');
}
}catch(e){
    e.displayErrors();
}

Kemungkinan besar Anda akan memiliki penangan kesalahan dalam file .js terpisah.

Anda akan melihat bahwa di firefox atau konsol kesalahan chrome, nomor baris kode (dan nama file) yang ditampilkan adalah baris (file) yang menampilkan pengecualian 'Kesalahan' dan bukan pengecualian 'errorHandler' yang benar-benar Anda inginkan untuk melakukan debugging mudah. Melempar pengecualian Anda sendiri itu bagus, tetapi pada proyek besar menemukannya bisa menjadi masalah, terutama jika mereka memiliki pesan yang serupa. Jadi, yang dapat Anda lakukan adalah meneruskan referensi ke objek Error kosong yang sebenarnya ke penangan kesalahan Anda, dan referensi tersebut akan menyimpan semua informasi yang Anda inginkan (misalnya di firefox Anda bisa mendapatkan nama file, dan nomor baris, dll. ; di chrome Anda mendapatkan sesuatu yang serupa jika Anda membaca properti 'stack' dari instance Error). Singkat cerita, Anda bisa melakukan sesuatu seperti ini:

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

Sekarang Anda bisa mendapatkan file aktual dan nomor baris yang memberikan pengecualian khusus kepada Anda.

rusu bogdan
sumber
4

Nomor baris sebenarnya adalah sesuatu yang statis, jadi jika Anda hanya menginginkannya untuk pencatatan maka nomor itu dapat diproses sebelumnya dengan sesuatu seperti gulp. Saya telah menulis plugin gulp kecil yang melakukan hal itu:

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'])

Ini akan melampirkan nama file dan baris ke semua log dari console.log, jadi console.log(something)akan menjadi console.log('filePath:fileNumber', something). Keuntungannya adalah sekarang Anda dapat menggabungkan file Anda, mentranspilasinya ... dan Anda masih akan mendapatkan barisnya

Gabriel Furstenheim
sumber
Ini sepertinya merupakan saran yang bagus untuk situasi di mana transpiler digunakan (misalnya, saat menggunakan TypeScript). Terima kasih!
Andy King
4

Saya menyadari ini adalah pertanyaan lama tetapi sekarang ada metode yang disebut console.trace("Message")yang akan menunjukkan nomor baris dan rantai panggilan metode yang mengarah ke log bersama dengan pesan yang Anda sampaikan. Info lebih lanjut tentang trik javascript logging tersedia di sini di freecodecamp dan posting blog medium ini

Japheth Ongeri - inkalimeva
sumber
3

Jika Anda ingin mengetahui nomor baris untuk tujuan debugging, atau hanya selama pengembangan (Untuk suatu alasan atau lainnya), Anda dapat menggunakan Firebug (ekstensi Firefox) dan membuat pengecualian.

Edit :

Jika Anda benar-benar perlu melakukan itu dalam produksi karena suatu alasan, Anda dapat melakukan pra-proses file javascript Anda agar setiap fungsi melacak baris tempat Anda berada. Saya tahu beberapa kerangka kerja yang menemukan cakupan kode menggunakan ini (seperti JSCoverage ).

Misalnya, panggilan awal Anda adalah:

function x() {
  1 + 1;
  2 + 2;
  y();
}

Anda bisa menulis preprocessor untuk membuatnya menjadi:

function x() {
  var me = arguments.callee;
  me.line = 1;
  1 + 1;
  me.line = 2;
  2 + 2;
  me.line = 3;
  y();
}

Kemudian y(), Anda dapat menggunakan arguments.callee.caller.lineuntuk mengetahui baris dari mana itu dipanggil, seperti:

function y() {
  alert(arguments.callee.caller.line);
}
Sinan Taifour
sumber
1
Terima kasih, saya ingin ini dalam produksi untuk alasan dukungan. Saya telah menemukan beberapa kode yang memungkinkan Anda untuk melihat tumpukan panggilan dari semua aliran sampai metode, tetapi tidak memiliki nomor baris di mana metode dipanggil. Saya kira solusi mudah untuk itu?
Tal
3

Beginilah cara saya melakukannya, saya telah mengujinya di Firefox dan Chrome. Ini memungkinkan untuk memeriksa nama file dan nomor baris dari tempat asal fungsi tersebut dipanggil.

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);
    }
}
Dilshan Liyanage
sumber
2

Inilah yang saya tulis berdasarkan info yang ditemukan di forum ini:

Ini adalah bagian dari MyDebugNamespace, Debug tampaknya dicadangkan dan tidak akan berfungsi sebagai nama namespace.

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

...

Bagaimana cara menelepon:

    MyDebugNamespace.Assert(new Error(""), (null != someVar), "Something is wrong!")

Saya menyertakan dua fungsi dengan jumlah variabel argumen yang memanggil kode dasar ini di ruang nama saya sehingga secara opsional menghilangkan pesan atau kesalahan dalam panggilan.

Ini berfungsi dengan baik dengan Firefox, IE6 dan Chrome melaporkan nama file dan lineNumber sebagai tidak ditentukan.

pasx
sumber
2

kode berikut berfungsi untuk saya di Mozilla dan Chrome.

Fungsi log-nya yang menunjukkan nama file dan garis pemanggil.

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);
}
Noampz
sumber
Sepertinya ada sesuatu yang hilang. Saya mendapatkan:SyntaxError: function statement requires a name,log: function (arg) {
spiderplant0
Saya suka ide ini, tetapi nomor barisnya salah untuk saya.
Ryan
2

Kontribusi saya pada kesalahan khusus di JavaScript:

  1. Pertama, saya setuju dengan pria @BT ini di Mewarisi dari objek Error - di mana properti pesan? , kami harus membangunnya dengan benar (sebenarnya Anda harus menggunakan pustaka objek js, favorit saya: 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. kemudian, kita harus mendefinisikan fungsi penanganan kesalahan global (opsional) atau, mereka akan berakhir ke mesin:

    window.onerror = printError; 
    function printError(msg, url, line){
        document.getElementById('test').innerHTML = msg+'<br>at: '+url+'<br>line: '+line;
        return true;
    }
  3. akhirnya, kita harus membuang kesalahan khusus kita dengan hati-hati:

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

Hanya saja, saat meneruskan parameter ketiga sebagai new Error() kita dapat melihat tumpukan dengan fungsi dan nomor baris!

Pada 2, fungsi tersebut juga dapat menangani kesalahan yang dilemparkan oleh mesin juga.

Tentu saja, pertanyaan sebenarnya adalah apakah kita benar-benar membutuhkannya dan kapan; ada kasus (99% menurut saya) di mana pengembalian anggun falsesudah cukup dan hanya menyisakan beberapa poin penting untuk ditampilkan dengan dilempar kesalahan.

Contoh: http://jsfiddle.net/centurianii/m2sQ3/1/

centurian
sumber
2
console.log(new Error);

Ini akan menunjukkan kepada Anda seluruh trek.

RatajS
sumber
1

Untuk menentukan di baris mana ada sesuatu, Anda harus mencari semua kode untuk kode yang menempati baris minat tertentu dan menghitung karakter "\ n" dari atas ke yang menarik ini dan menambahkan 1.

Saya sebenarnya melakukan hal ini dalam aplikasi yang saya tulis. Ini adalah validator praktik terbaik untuk HTML dan masih dalam pengembangan, tetapi proses keluaran kesalahan yang Anda minati telah selesai.

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


sumber
garis minat tertentu bisa banyak ... Jika saya memiliki metode yang sama dipanggil beberapa kali dari metode lain, bagaimana saya bisa tahu (dalam metode lain) dari mana panggilan itu berasal?
Tal
Anda tidak akan dapat menganalisis interpretasi JavaScript pada waktu eksekusi dari luar interpreter. Anda dapat menulis program untuk melacak jalur eksekusi dalam program Anda, tetapi program itulah yang sedang dieksekusi dan bukan kode yang ingin Anda analisis. Ini biasanya merupakan tugas rumit yang dilakukan secara manual dengan bantuan alat. Jika Anda benar-benar ingin melihat apa yang terjadi dalam kode Anda saat dijalankan maka buatlah itu menulis meta-data ke layar yang memberi tahu Anda ingin keputusan sedang mengeksekusi bagian mana yang lain.
-2

Jawabannya sederhana. Tidak dan Tidak (Tidak).

Pada saat javascript menjalankan konsep file / url sumber yang berasal sudah hilang.

Juga tidak ada cara untuk menentukan nomor baris karena sekali lagi pada saat eksekusi pengertian kode "baris" tidak lagi berarti di Javascript.

Implementasi khusus dapat menyediakan hook API untuk memungkinkan akses kode priviledged ke detail tersebut untuk tujuan debugging, tetapi API ini tidak diekspos ke kode Javascript standar biasa.

AnthonyWJones
sumber
Di firefox pengecualian mencakup informasi seperti itu ... apakah mungkin setidaknya di firefox?
Zoidberg
Saat Anda meluncurkan MS Script debugger dan meletakkan beberapa breakpoint, Anda akan melihat di tumpukan panggilan dari mana tepatnya Anda berasal. Ini karena pengait khusus?
Tal
"lagi pada saat eksekusi gagasan kode" baris "tidak lagi berarti dalam Javascript." Hah? JS sudah menunjukkan nomor baris setiap kali Anda menjalankan console.log ()
mikemaccana
@Anony. Ini dengan jelas bertentangan dengan 'Tidak dan Tidak (Tidak)' yang agak absolut.
mikemaccana
@nailer: Kembali pada tahun 2009 di semua browser utama, dalam hal apa jawaban saya bertentangan. Ingat pertanyaan yang ada adalah tentang penemuan, dalam menjalankan javascript, dari nomor baris callee?
AnthonyWJones