JavaScript arayan işlevi satır numarası nasıl alınır? JavaScript arayan kaynak URL'si nasıl alınır?


109

JavaScript arayan işlev adını almak için aşağıdakileri kullanıyorum:

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

Yöntemin çağrıldığı satır numarasını keşfetmenin bir yolu var mı?

Ayrıca, yöntemin çağrıldığı JavaScript dosyasının adını almanın bir yolu var mı? Veya kaynak URL?


2
Bunun IE'de mümkün olduğunu sanmıyorum, aksi takdirde hiçbir ayrıntı vermeyen CRAPPY hata mesajlarını orada dolaşmanın bir yolunu bulabiliriz. Ama mümkünse ben de bilmek isterim!
Zoidberg

Evet. İşte her tarayıcının tescilli yöntemlerini kullanan bir çapraz tarayıcı işlevi: github.com/eriwen/javascript-stacktrace [sabit bağlantı]
scotts

Yanıtlar:


99

Bu benim için chrome / QtWebView'da çalışıyor

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

Düğümde de çalışır. Bunu özel log () işlevinize (ihtiyacınız olan diğer yararlı geçici çözümleri ekler - örneğin, Chrome dizisi günlüğü için sabit) ve log () olarak adlandırdığınız yerden satır numaralarını ekleyin.
mikemaccana

60
Hatayı atmanıza gerek yok; basitçe oluşturmak yeterli:var caller_line = (new Error).stack.split("\n")[4]
ELLIOTTCABLE

2
Bir FF / Webkit "standartlaştırılmış" yanıtı almak için bu öneriyi başka bir benzer yanıtla birleştirdi - bkz. Stackoverflow.com/a/14841411/1037948
drzaus

1
PhantomJS'de de çalışır, ancak onu atmanız gerekir, aksi takdirde "yığın" özniteliği hatada ayarlanmaz.
Joshua Richardson

1
@ELLIOTTCABLE aslında iOS safari gibi bazı tarayıcılarda istisnayı atmanız gerekiyor! Öyleyse neden yapmıyorsun?
arctelix

26

kangax'ın çözümü gereksiz try..catch kapsamı getiriyor. JavaScript'teki bir şeyin satır numarasına erişmeniz gerekiyorsa (Firefox veya Opera kullandığınız sürece), sadece erişin (new Error).lineNumber.


11
Merhaba, bu eklenti için teşekkürler. Önceki aramadan hat numarası almanın mümkün olup olmadığını biliyor musunuz? Diyelim ki yöntem A, B'yi çağırıyor ve şimdi BI'da, A'nın altındaki hangi satırda arama yapıldığını bilmek istiyor musunuz?
Tal

85
Bu işaretlenir, ancak soruyu yanıtlamaz; bu, arayan işlevinin hat numarasının nasıl alınacağıdır .
mikemaccana

3
Ayrıca bu son derece sınırlıdır. En iyi çözüm, tüm modern tarayıcılarda mevcut olan error.stack dosyasında bir hata atmak ve normal ifadeyi kullanmaktır. Bu yolu, dosyayı, satırı ve sütunu kolayca çıkarabilirsiniz. Sorun değil.
arctelix

13

Bu yanıtların çoğunun, yalnızca normal durumlar için yararlı hata ayıklama izleri çıkarmak yerine bir hatayı ele almak istediğinizi varsaymasına şaşırdım.

Örneğin, bunun gibi bir console.logsarmalayıcı kullanmayı seviyorum:

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

Bu, konsoluma aşağıdaki gibi bir çıktı yazdırmakla sonuçlanır:

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

Bkz https://stackoverflow.com/a/27074218/ ve doğru hat numarası ile console.log için düzgün bir sargı?


1
firefox tarayıcısı için çalışır, ancak node.js için çalışmaz.
fermuar

1
düğüm altında stack [2] '
yi kaydetmelisiniz

5

Bu genellikle mevcut bağlamdan bir hata atılarak elde edilir; sonra lineNumberve gibi özellikler için hata nesnesini analiz etmek fileName(bazı tarayıcılarda var)

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

var err = getErrorObject();

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

callee.callerMülkün kullanımdan kaldırıldığını (ve ilk etapta ECMA 3. baskıda hiçbir zaman gerçekten bulunmadığını) unutmayın .

Ayrıca derleme işlevinin uygulamaya bağlı olarak belirtildiğini ve bu nedenle oldukça beklenmedik sonuçlar verebileceğini unutmayın. Bunun hakkında burada ve burada yazdım .


Teşekkürler, bu kodu ihtiyacım olan uygulamaya eklemek biraz sorunlu görünüyor. (bazı js izleme çerçevesi) Kullanabileceğim, kullanımdan kaldırılmamış başka bir yöntem biliyor musunuz?
Tal

Kullanımdan kaldırılanlara güvenmeden hata nesnesini inceleyebilmelisiniz callee.caller.
kangax

Hatayı atmanıza gerek yok. Bir betikteki mevcut satır numarasına erişmek için (yeni Hata) .lineNumber'ı kullanırsınız.
Eli Gray

@Elijah FF3'te gördüğüm şey bu. Öte yandan WebKit, lineyalnızca hata atıldığında doldurulur .
kangax

Callee.caller'ın yerine geçen nedir? İşlev adını almam gerekirse?
Tal

4

Görünüşe göre biraz geç kaldım :), ama tartışma oldukça ilginç, bu yüzden .. işte başlıyor ... Bir hata işleyici oluşturmak istediğinizi ve kendi istisna giderici sınıfınızı aşağıdaki gibi kullandığınızı varsayarsak:

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

Ve kodunuzu şu şekilde sarmalıyorsunuz:

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

Hata işleyiciyi büyük olasılıkla ayrı bir .js dosyasında bulacaksınız.

Firefox veya chrome'un hata konsolunda gösterilen kod satırı numarasının (ve dosya adının), hata ayıklama yapmak için gerçekten istediğiniz 'errorHandler' istisnasını değil, 'Error' istisnasını atan satır (dosya) olduğunu fark edeceksiniz. kolay. Kendi istisnalarınızı atmak harikadır, ancak büyük projelerde bunları bulmak, özellikle de benzer mesajlar varsa, oldukça sorun olabilir. Yani, yapabileceğiniz şey, hata işleyicinize gerçek bir boş Error nesnesine bir referans iletmektir ve bu referans istediğiniz tüm bilgileri tutacaktır (örneğin firefox'ta dosya adını ve satır numarasını vb. Alabilirsiniz. ; chrome'da, Error örneğinin 'stack' özelliğini okursanız benzer bir şey elde edersiniz). Uzun lafın kısası, şöyle bir şey yapabilirsiniz:

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

Artık size özel istisna atan gerçek dosya ve satır numarasını alabilirsiniz.


4

Satır numarası aslında statik bir şeydir, bu yüzden sadece günlük kaydı için istiyorsanız, o zaman yudum gibi bir şeyle önceden işlenebilir. Tam olarak bunu yapan küçük bir yudum eklentisi yazdım :

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

Bu console.log tüm günlükleri dosya adını ve satır ekler, böylece console.log(something)hale gelecektir console.log('filePath:fileNumber', something). Avantajı artık dosyalarınızı birleştirebilir, aktarabilirsiniz ... ve yine de satırı alacaksınız


Bu, bir aktarıcının kullanıldığı durumlar için harika bir öneri gibi görünüyor (örneğin, TypeScript kullanırken). Teşekkür ederim!
Andy King


3

Satır numarasını hata ayıklama amacıyla veya yalnızca geliştirme sırasında (bir nedenle veya başka bir nedenle) bilmek istiyorsanız, Firebug'ı (bir Firefox uzantısı) kullanabilir ve bir istisna atabilirsiniz .

Düzenle :

Bunu herhangi bir nedenle üretimde gerçekten yapmanız gerekiyorsa, her işlevin üzerinde bulunduğu satırı takip etmesi için javascript dosyalarınızı önceden işleyebilirsiniz. Kod kapsamını bulan bazı çerçevelerin bunu kullandığını biliyorum ( JSCoverage gibi ).

Örneğin, orijinal aramanızın şöyle olduğunu varsayalım:

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

Bunu yapmak için bir önişlemci yazabilirsiniz:

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

Ardından içinde y(), arguments.callee.caller.lineçağrıldığı satırı bilmek için kullanabilirsiniz , örneğin:

function y() {
  alert(arguments.callee.caller.line);
}

1
Teşekkürler, destek nedenlerinden dolayı üretimde bunu yapmak isterim. Yönteme kadar tüm akışların çağrı yığınını görmenizi sağlayan bir kod buldum, ancak yöntemlerin çağrıldığı satır numaralarına sahip değil. Sanırım bunun için kolay bir çözüm?
Tal

3

Ben de böyle yaptım, hem Firefox hem de Chrome'da test ettim. Bu, işlevin çağrıldığı yerin dosya adını ve satır numarasını kontrol etmeyi mümkün kılar.

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

İşte bu forumda bulunan bilgilere dayanarak yazdıklarım:

Bu, MyDebugNamespace'in bir parçasıdır, Debug görünüşe göre ayrılmış ve ad alanı adı olarak kullanılmayacak.

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

...

Nasıl aranır:

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

Çağrılarda isteğe bağlı olarak mesaj veya hatayı atlamak için bu temel kodu çağıran değişken sayıda argümana sahip iki işlev ekledim.

Bu, Firefox, IE6 ve Chrome ile iyi çalışır, fileName ve lineNumber öğelerini tanımsız olarak bildirir.


2

Aşağıdaki kod Mozilla ve Chrome'da benim için çalışıyor.

Dosyanın adını ve arayanın satırını gösteren günlük işlevi.

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

Görünüşe göre bir şey eksik. Anlıyorum:SyntaxError: function statement requires a name,log: function (arg) {
örümcek bitkisi0

Bu fikri sevdim ama satır numaraları benim için yanlış çıkıyor.
Ryan

2

JavaScript'teki özel hatalara katkım:

  1. İlk olarak, Hata nesnesinden Devralma konusunda bu @BT adamına katılıyorum - mesaj özelliği nerede? , onu doğru bir şekilde oluşturmalıyız (aslında bir js nesne kitaplığı kullanmanız gerekiyor, benim favorim: 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. daha sonra, genel bir hata işleme işlevi (isteğe bağlı) tanımlamalıyız, aksi takdirde bunlar motora ulaşır:

    window.onerror = printError; 
    function printError(msg, url, line){
        document.getElementById('test').innerHTML = msg+'<br>at: '+url+'<br>line: '+line;
        return true;
    }
  3. son olarak, özel hatalarımızı dikkatlice atmalıyız:

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

Yalnızca, üçüncü parametreyi geçerken, new Error()işlevi ve satır numaralarını içeren yığını görebiliriz!

2'de, işlev aynı zamanda motor tarafından atılan hatayı da ele alabilir.

Tabii ki asıl soru, buna gerçekten ihtiyacımız olup olmadığı ve ne zaman olacağıdır; Zarif bir dönüşün falseyeterli olduğu ve sadece bir hata atılarak gösterilecek bazı kritik noktaları bıraktığı durumlar (bence% 99) var .

Örnek: http://jsfiddle.net/centurianii/m2sQ3/1/


2
console.log(new Error);

Size tüm parçayı gösterecek.


1

Bir şeyin hangi satırda olduğunu belirlemek için, belirli ilgilenilen satırı işgal eden kod için tüm kodu aramanız ve ilgilendiğiniz yere kadar "\ n" karakterlerini saymanız ve 1 eklemeniz gerekir.

Aslında bunu yazdığım bir uygulamada yapıyorum. HTML için bir en iyi uygulama doğrulayıcıdır ve hala büyük ölçüde geliştirilme aşamasındadır, ancak ilgilenebileceğiniz hata çıktı süreci tamamlanmıştır.

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


belirli ilgi alanı çok sayıda olabilir ... Başka bir yöntemden birkaç kez çağrılan aynı yönteme sahipsem, aramanın nereden geldiğini (bu diğer yöntemde) nasıl bilebilirim?
Tal

Yorumlayıcı dışından yürütme sırasında JavaScript yorumunu analiz edemezsiniz. Programınızdaki yürütme yolunu izlemek için bir program yazabilirsiniz, ancak bu, analiz etmek istediğiniz kod değil, çalıştıran program olacaktır. Bu tipik olarak, araçlar yardımıyla manuel olarak gerçekleştirilen karmaşık bir görevdir. Kodunuz çalışırken gerçekten neler olup bittiğini görmek istiyorsanız, o zaman kararların başka hangi parçaları yürüttüğünü istediğinizi söyleyen ekrana meta veri yazmasını sağlayın.

-2

Cevaplar basit. Hayır ve Hayır (Hayır).

Javascript, gelenin gittiği kaynak dosyalar / url'ler kavramını çalıştırdığı zaman.

Bir satır numarasını belirlemenin de bir yolu yoktur, çünkü yürütme sırasında kod "satırlar" kavramı artık Javascript'te anlamlı değildir.

Belirli uygulamalar, hata ayıklama amacıyla bu tür ayrıntılara ayrıcalıklı kod erişimine izin vermek için API kancaları sağlayabilir, ancak bu API'ler sıradan standart Javascript koduna maruz kalmaz.


Firefox'ta istisnalar bu tür bilgileri içerir ... en azından firefox'ta mümkün olabilir mi?
Zoidberg

MS Script hata ayıklayıcısını başlattığınızda ve bir kesme noktası koyduğunuzda, çağrı yığınında tam olarak nereden geldiğinizi görürsünüz. Bunun nedeni özel kancalar mı?
Tal

"yine yürütme sırasında kod" satırları "kavramı artık Javascript'te anlamsızdır." Huh? JS zaten console.log () 'u her çalıştırdığınızda satır numarasını gösteriyor
mikemaccana

@AnthonyWJones Evet. Biraz mutlak olan 'Hayır ve Hayır (Hayır)' ile düzgün bir şekilde çelişiyor.
mikemaccana

@nailer: 2009'da tüm büyük tarayıcılarda, cevabım hangi yönden çelişiyor? Elinizdeki sorunun javascript çalıştırırken callee'nin satır numarasının keşfi ile ilgili olduğunu unutmayın.
AnthonyWJones
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.