Làm cách nào để lấy số dòng hàm người gọi JavaScript? Làm cách nào để lấy URL nguồn của trình gọi JavaScript?


109

Tôi đang sử dụng phần sau để lấy tên hàm trình gọi JavaScript:

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

Có cách nào để khám phá số dòng mà từ đó phương thức được gọi không?

Ngoài ra, có cách nào để lấy tên của tệp JavaScript mà phương thức được gọi từ đó không? Hay URL nguồn?


2
Tôi không nghĩ rằng điều này có thể xảy ra trong IE, nếu không chúng tôi sẽ có cách để giải quyết vấn đề lỗi CRAPPY không cung cấp thông tin chi tiết. Nhưng nếu có thể thì tôi cũng YÊU được biết!
Zoidberg

Đúng. Đây là một chức năng trình duyệt chéo sử dụng các phương pháp độc quyền của từng trình duyệt: github.com/eriwen/javascript-stacktrace [fixed link]
scotts Ngày

Câu trả lời:


99

Điều này phù hợp với tôi trong 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);

Hoạt động trong nút quá. Đưa cái này vào bên trong hàm log () tùy chỉnh của bạn (bổ sung bất kỳ cách giải quyết hữu ích nào khác mà bạn cần - ví dụ: cố định cho ghi nhật ký mảng Chrome) và số dòng tĩnh từ bất kỳ nơi nào bạn gọi là log ().
mikemaccana

60
Không cần phải ném lỗi; chỉ cần tạo nó là đủ:var caller_line = (new Error).stack.split("\n")[4]
ELLIOTTCABLE

2
Đã hợp nhất đề xuất này với một câu trả lời tương tự khác để nhận được phản hồi "chuẩn hóa" FF / Webkit - xem stackoverflow.com/a/14841411/1037948
drzaus

1
Hoạt động trong PhantomJS cũng vậy, nhưng bạn phải ném nó, nếu không thuộc tính "ngăn xếp" không được đặt trên lỗi.
Joshua Richardson

1
@ELLIOTTCABLE thực tế trong một số trình duyệt như iOS safari, bạn cần phải loại bỏ ngoại lệ! Vậy tại sao không làm điều đó?
arctelix

26

Giải pháp của kangax giới thiệu phạm vi try..catch không cần thiết. Nếu bạn cần truy cập số dòng của thứ gì đó trong JavaScript (miễn là bạn đang sử dụng Firefox hoặc Opera), chỉ cần truy cập (new Error).lineNumber.


11
Xin chào, Cảm ơn vì addon đó. bạn có biết nếu nó có thể nhận được số đường dây từ cuộc gọi trước đó? Giả sử phương thức A gọi B, và bây giờ trong BI muốn biết lệnh gọi được thực hiện ở dòng nào dưới A?
Tal

85
Điều này được đánh dấu, nhưng không trả lời câu hỏi, đó là làm thế nào để lấy số dòng của hàm người gọi .
mikemaccana

3
Ngoài ra, điều này là cực kỳ hạn chế. Giải pháp tốt nhất là tạo ra một lỗi và sử dụng regex trên error.stack có sẵn trong tất cả các trình duyệt hiện đại. Bạn có thể dễ dàng trích xuất đường dẫn, tệp, dòng và cột đó. Không vấn đề gì.
arctelix

13

Tôi rất ngạc nhiên khi hầu hết các câu trả lời này giả định rằng bạn muốn xử lý một lỗi hơn là chỉ xuất ra các dấu vết gỡ lỗi hữu ích cho các trường hợp thông thường.

Ví dụ: tôi thích sử dụng một console.logtrình bao bọc như thế này:

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

Điều này kết thúc in một đầu ra chẳng hạn như sau vào bảng điều khiển của tôi:

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

Xem https://stackoverflow.com/a/27074218/ và cả Trình bao bọc thích hợp cho console.log với số dòng chính xác?


1
hoạt động cho trình duyệt firefox, nhưng không hoạt động cho node.js.
dây kéo

1
dưới nút, bạn phải ghi ngăn xếp [2]
monika mevenkamp

5

Điều này thường đạt được bằng cách ném một lỗi từ ngữ cảnh hiện tại; sau đó phân tích đối tượng lỗi cho các thuộc tính như lineNumberfileName(một số trình duyệt có)

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

var err = getErrorObject();

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

Đừng quên rằng thuộc callee.callertính không được dùng nữa (và chưa bao giờ thực sự có trong ECMA phiên bản thứ 3 ngay từ đầu).

Cũng nên nhớ rằng việc dịch ngược hàm được chỉ định phụ thuộc vào việc triển khai và do đó có thể mang lại kết quả khá bất ngờ. Tôi đã viết về nó ở đâyở đây .


Cảm ơn, có vẻ như có một chút vấn đề khi thêm mã này vào ứng dụng tôi cần. (một số khuôn khổ theo dõi js) Bạn có biết bất kỳ phương pháp nào khác không bị phản đối mà tôi có thể sử dụng không?
Tal

Bạn sẽ có thể kiểm tra đối tượng lỗi mà không cần dựa vào đối tượng không dùng nữa callee.caller.
kangax

Bạn không cần phải ném Error. Bạn chỉ cần sử dụng (Lỗi mới) .lineNumber để truy cập số dòng hiện tại trong một tập lệnh.
Eli Grey

@Elijah Đó là những gì tôi thấy trong FF3. Mặt khác, WebKit linechỉ điền khi có lỗi.
kangax

Thay thế cho callee.caller là gì? Nếu tôi cần lấy tên hàm?
Tal

4

Có vẻ như tôi đến muộn :), nhưng cuộc thảo luận khá thú vị nên .. đây rồi ... Giả sử bạn muốn tạo một trình xử lý lỗi và bạn đang sử dụng lớp xử lý ngoại lệ của riêng mình như:

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

Và bạn đang quấn mã của mình như thế này:

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

Hầu hết có thể bạn sẽ có trình xử lý lỗi trong một tệp .js riêng biệt.

Bạn sẽ nhận thấy rằng trong bảng điều khiển lỗi của firefox hoặc chrome, số dòng mã (và tên tệp) được hiển thị là dòng (tệp) đưa ra ngoại lệ 'Lỗi' chứ không phải ngoại lệ 'errorHandler' mà bạn thực sự muốn để gỡ lỗi dễ dàng. Bỏ qua các ngoại lệ của riêng bạn là rất tốt nhưng đối với các dự án lớn, việc xác định vị trí của chúng có thể là một vấn đề, đặc biệt nếu chúng có các thông điệp tương tự. Vì vậy, những gì bạn có thể làm là chuyển một tham chiếu đến một đối tượng Lỗi thực sự trống cho trình xử lý lỗi của bạn và tham chiếu đó sẽ chứa tất cả thông tin bạn muốn (ví dụ: trong firefox, bạn có thể lấy tên tệp và số dòng, v.v. ; trong chrome, bạn nhận được một cái gì đó tương tự nếu bạn đọc thuộc tính 'ngăn xếp' của trường hợp Lỗi). Câu chuyện ngắn, bạn có thể làm như sau:

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

Bây giờ bạn có thể nhận được tệp thực tế và số dòng đã đưa ra ngoại lệ tùy chỉnh cho bạn.


4

Số dòng thực sự là một cái gì đó tĩnh, vì vậy nếu bạn chỉ muốn nó để ghi nhật ký thì nó có thể được xử lý trước với một cái gì đó như gulp. Tôi đã viết một plugin gulp nhỏ thực hiện chính xác điều đó:

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

Điều này sẽ đính kèm tên tệp và dòng vào tất cả các bản ghi từ console.log, như vậy console.log(something)sẽ trở thành console.log('filePath:fileNumber', something). Ưu điểm là bây giờ bạn có thể nối các tệp của mình, chuyển tải chúng ... và bạn vẫn sẽ nhận được dòng


Đây có vẻ như là một gợi ý tuyệt vời cho các trường hợp sử dụng trình chuyển tiếp (ví dụ: khi sử dụng TypeScript). Cảm ơn bạn!
Andy King,

4

Tôi nhận ra đây là một câu hỏi cũ nhưng bây giờ có một phương thức được gọi là console.trace("Message")sẽ hiển thị cho bạn số dòng và chuỗi lệnh gọi phương thức dẫn đến nhật ký cùng với thông báo bạn chuyển nó. Thông tin thêm về thủ thuật ghi nhật ký javascript có sẵn tại freecodecampbài đăng blog phương tiện này


3

Nếu bạn muốn biết số dòng cho mục đích gỡ lỗi hoặc chỉ trong quá trình phát triển (Vì lý do này hay lý do khác), bạn có thể sử dụng Firebug (một tiện ích mở rộng của Firefox) và đưa ra một ngoại lệ.

Chỉnh sửa :

Nếu bạn thực sự cần làm điều đó trong sản xuất vì lý do nào đó, bạn có thể xử lý trước các tệp javascript của mình để mỗi chức năng theo dõi dòng nó đang hoạt động. Tôi biết một số khung công tác tìm thấy mức độ phù hợp của mã sử dụng điều này (chẳng hạn như JSCoverage ).

Ví dụ: giả sử cuộc gọi ban đầu của bạn là:

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

Bạn có thể viết một bộ tiền xử lý để biến nó thành:

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

Sau đó y(), bạn có thể sử dụng arguments.callee.caller.lineđể biết dòng mà từ đó nó được gọi, chẳng hạn như:

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

1
Cảm ơn, tôi muốn điều này trong sản xuất vì lý do hỗ trợ. Tôi đã tìm thấy một số mã cho phép bạn xem ngăn xếp lệnh gọi của tất cả các luồng cho đến phương thức, nhưng nó không có số dòng nơi các phương thức được gọi. Tôi đoán để giải pháp dễ dàng cho điều đó?
Tal

3

Đây là cách tôi đã thực hiện, tôi đã thử nghiệm nó trên cả Firefox và Chrome. Điều này giúp bạn có thể kiểm tra tên tệp và số dòng của nơi hàm được gọi từ đó.

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

Đây là những gì tôi đã viết dựa trên thông tin tìm thấy trên diễn đàn này:

Đây là một phần của MyDebugNamespace, Debug dường như được dành riêng và sẽ không hoạt động như tên không gian tên.

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

...

Cách gọi:

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

Tôi đã bao gồm hai hàm với số lượng đối số thay đổi gọi mã cơ sở này trong không gian tên của tôi để tùy chọn bỏ qua thông báo hoặc lỗi trong các cuộc gọi.

Điều này hoạt động tốt với Firefox, IE6 và Chrome báo cáo tên tệp và số dòng là không xác định.


2

mã sau phù hợp với tôi trong Mozilla và Chrome.

Chức năng nhật ký của nó hiển thị tên tệp và dòng của trình gọi.

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

Hình như còn thiếu thứ gì đó. Tôi nhận được:SyntaxError: function statement requires a name,log: function (arg) {
spiderplant0

Tôi thích ý tưởng này, nhưng số dòng xuất hiện không chính xác đối với tôi.
Ryan

2

Đóng góp của tôi cho các lỗi tùy chỉnh trong JavaScript:

  1. Đầu tiên, tôi đồng ý với anh chàng @BT này tại Kế thừa từ đối tượng Lỗi - thuộc tính thông báo ở đâu? , chúng ta phải xây dựng nó đúng cách (thực ra bạn phải sử dụng thư viện đối tượng js, yêu thích của tôi: 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. sau đó, chúng ta nên xác định một chức năng xử lý lỗi chung (tùy chọn) hoặc, chúng sẽ kết thúc với động cơ:

    window.onerror = printError; 
    function printError(msg, url, line){
        document.getElementById('test').innerHTML = msg+'<br>at: '+url+'<br>line: '+line;
        return true;
    }
  3. cuối cùng, chúng ta nên cẩn thận loại bỏ các lỗi tùy chỉnh của mình:

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

Chỉ khi truyền tham số thứ ba là new Error()chúng ta có thể thấy ngăn xếp với hàm và số dòng!

Ở mức 2, chức năng này cũng có thể xử lý lỗi do động cơ gây ra.

Tất nhiên, câu hỏi thực sự là nếu chúng ta thực sự cần nó và khi nào; có những trường hợp (theo ý kiến ​​của tôi là 99%) trong đó việc trả lại một cách ân cần falselà đủ và chỉ để lại một số điểm quan trọng được hiển thị với việc ném một lỗi.

Ví dụ: http://jsfiddle.net/centurianii/m2sQ3/1/


2
console.log(new Error);

Nó sẽ hiển thị cho bạn toàn bộ bản nhạc.


1

Để xác định dòng nào đó nằm trên dòng nào, bạn phải tìm kiếm tất cả mã cho mã chiếm dòng quan tâm cụ thể và đếm các ký tự "\ n" từ đầu đến dòng quan tâm này và thêm 1.

Tôi thực sự đang làm điều này trong một ứng dụng tôi đang viết. Nó là một trình xác thực thực tiễn tốt nhất cho HTML và vẫn đang được phát triển nhiều, nhưng quá trình xuất lỗi mà bạn quan tâm đã hoàn tất.

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


dòng quan tâm cụ thể có thể có nhiều ... Nếu tôi có cùng một phương thức được gọi nhiều lần từ một phương thức khác, làm thế nào tôi có thể biết (trong phương thức khác đó) cuộc gọi đến từ đâu?
Tal

Bạn sẽ không thể phân tích thông dịch JavaScript tại thời điểm thực thi từ bên ngoài trình thông dịch. Bạn có thể viết một chương trình để theo dõi đường dẫn thực thi trong chương trình của mình, nhưng nó sẽ là chương trình đang thực thi chứ không phải mã mà bạn muốn phân tích. Đây thường là một tác vụ phức tạp được thực hiện thủ công với sự trợ giúp của các công cụ. Nếu bạn thực sự muốn xem những gì đang xảy ra trong mã của bạn khi nó thực thi thì hãy yêu cầu nó ghi siêu dữ liệu vào màn hình cho bạn biết bạn muốn các quyết định đang thực thi phần nào khác.

-2

Câu trả lời rất đơn giản. No and No (Không).

Vào thời điểm javascript đang chạy khái niệm về các tệp / url nguồn mà từ đó nó không còn nữa.

Cũng không có cách nào để xác định số dòng vì một lần nữa vào thời điểm thực thi, khái niệm mã "dòng" không còn có ý nghĩa trong Javascript.

Các triển khai cụ thể có thể cung cấp các móc API để cho phép mã riêng tư truy cập vào các chi tiết như vậy nhằm mục đích gỡ lỗi nhưng các API này không tiếp xúc với mã Javascript tiêu chuẩn thông thường.


Trong firefox các trường hợp ngoại lệ bao gồm thông tin như vậy ... ít nhất nó sẽ có thể trong firefox?
Zoidberg

Khi bạn khởi chạy trình gỡ lỗi MS Script và đặt một số điểm ngắt, bạn sẽ thấy trong ngăn xếp cuộc gọi chính xác nơi bạn đến. Đây là do móc chuyên dụng?
Tal

"một lần nữa vào thời điểm thực thi, khái niệm mã" dòng "không còn có ý nghĩa trong Javascript." Huh? JS đã cho thấy mọi số dòng bạn chạy console.log ()
mikemaccana

@AnthonyWJones Có. Nó hoàn toàn mâu thuẫn với 'No and No (Không)'.
mikemaccana

@nailer: Trở lại năm 2009 trên tất cả các trình duyệt chính, câu trả lời của tôi mâu thuẫn theo cách nào. Hãy ghi nhớ câu hỏi hiện tại là về khám phá, khi chạy javascript, số dòng của callee?
AnthonyWJones
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.