Xử lý ngoại lệ JavaScript


82

Kỹ thuật tốt nhất để bắt TẤT CẢ các ngoại lệ trong JavaScript là gì?

Rõ ràng, kỹ thuật tốt nhất là sử dụng try ... catch. Nhưng với các lệnh gọi lại không đồng bộ, v.v., điều đó có thể trở nên phức tạp.

Tôi biết trình duyệt IE và Gecko hỗ trợ window.onerror, nhưng còn Opera và Safari thì sao?

Dưới đây là một loạt các trường hợp thử nghiệm mà tôi muốn có giải pháp xử lý ngoại lệ trung tâm cho:

// ErrorHandler-Test1
var test = null;
test.arg = 5;
// ErrorHandler-Test2
throw (new Error("Hello"));
// ErrorHandler-Test3
throw "Hello again";
// ErrorHandler-Test4
throw {
    myMessage: "stuff",
    customProperty: 5,
    anArray: [1, 2, 3]
};
// ErrorHandler-Test5
try {
    var test2 = null;
    test2.arg = 5;
} catch(e) {
    ErrorHandler.handleError(e);
}
// ErrorHandler-Test6
try {
    throw (new Error("Goodbye"));
} catch(e) {
    ErrorHandler.handleError(e);
}
// ErrorHandler-Test7
try {
    throw "Goodbye again";
} catch(e) {
    ErrorHandler.handleError(e);
}
// ErrorHandler-Test8
try {
    throw {
        myMessage: "stuff",
        customProperty: 5,
        anArray: [1, 2, 3]
    };
} catch(e) {
    ErrorHandler.handleError(e);
}

Nếu bạn nghĩ về bất kỳ trường hợp thử nghiệm nào khác, vui lòng đề cập đến chúng. Một số trường hợp trong số này đề cập đến phương thức ErrorHandler.handleError. Đây chỉ là một hướng dẫn được đề xuất khi sử dụng try ... catch.


Chỉ vì rõ ràng là bạn đã không nhận thấy các nhận xét về câu trả lời của tôi: có vẻ như bạn đã từ chối tôi vì "đã nêu trong câu hỏi" khi nó được đọc là một câu hỏi: "nhưng còn Opera và Safari thì sao?" Tôi đã trả lời cụ thể một câu hỏi được đặt ra ở đây. WTF?
mí mắt,

1
Trong WebKit, window.onerrormất tích đã là một vấn đề kể từ năm 2003 , nhưng có vẻ như nó cuối cùng đã được giải quyết . Tất nhiên, Opera sẽ vẫn cố chấp.
josh3736,

FYI window.onerror hoạt động tốt trong - Firefox 7.0.1 - IE 8 - Chrome 16 - Opera 11.60
Vitaliy Kaplich

11
Không chắc tại sao điều này đã bị đóng cửa. Đã bỏ phiếu để mở lại.
ripper234

1
Đồng ý, đây là một câu hỏi hữu ích. Điều duy nhất tôi có thể nghĩ là casperOne sợ điều này sẽ trở thành một cuộc thảo luận về chiến tranh trình duyệt?
Jordan Reiter

Câu trả lời:


23

Nếu bạn sử dụng một thư viện như jQuery để gán tất cả các trình xử lý sự kiện của mình, bạn có thể sử dụng kết hợp window.onerrorvà gói mã trình xử lý sự kiện jQuery và trên hàm sẵn sàng với một chức năng xử lý lỗi (xem: Theo dõi lỗi JavaScript: Tại sao window.onerror là không đủ ).

  • window.onerror: bắt tất cả các lỗi trong IE (và hầu hết các lỗi trong Firefox), nhưng không làm được gì trong Safari và Opera.
  • Trình xử lý sự kiện jQuery: bắt lỗi sự kiện jQuery trong tất cả các trình duyệt.
  • Hàm sẵn sàng của jQuery: bắt lỗi khởi tạo trong tất cả các trình duyệt.

Tôi đã đọc bài báo không đưa ra bất kỳ giải pháp nào. Tôi không sử dụng jQuery, nhưng tôi lo lắng về những gì bạn đang ám chỉ. Bạn đang nói rằng jQuery đang ăn các ngoại lệ ?! Hay họ chỉ cung cấp chức năng ghi nhật ký (chỉ hữu ích sau khi câu hỏi ban đầu của tôi được trả lời)?
harley.333

jQuery không làm bất cứ điều gì đặc biệt với Exceptions. Nhưng nếu bạn sử dụng jQuery để thêm tất cả các sự kiện của mình, nó sẽ cung cấp cho bạn một nơi duy nhất để thêm câu lệnh try catch và mã xử lý lỗi như được giải thích trong liên kết thứ hai trong câu trả lời của tôi.
Karl

2
Các liên kết với điều kiện di chuyển: blogs.cozi.com/tech/2008/04/...
natacado

1
Điều này có còn đúng không? Tôi vừa thử cách onerrorxử lý thông thường trên Safari + Chrome và có vẻ như hoạt động bình thường.
Juri

Liên kết bạn đưa ra lý do tại sao "nó không đủ" là thông tin khá cũ và không phải là trường hợp bây giờ.
vsync

21

WebKit (Safari, Chrome, v.v.) hiện hỗ trợ onerror.

Bài gốc: Theo như tôi biết, WebKit / Safari không hỗ trợ onerrorsự kiện này. Đó là một sự xấu hổ chết tiệt.


19
Uh, không, không phải. Khi được hỏi trong câu hỏi: "nhưng còn Opera và Safari thì sao?"
mí mắt vào

Như trong, tôi đã trả lời cụ thể một câu hỏi được đặt ra trong bài đăng câu hỏi.
mí mắt,

8
Tôi nghĩ ý của anh ấy là "[tôi phải làm gì] về Opera và Safari [không có window.onerror]?"
nickf

10
@nickf, có thể, nhưng nếu vậy thì nó bị diễn đạt rất tệ và cách diễn giải của tôi khó hiểu nhất và tốt nhất là có khả năng xảy ra cao nhất. Đó là một lý do khá tồi để mọi người bỏ phiếu cho câu trả lời của tôi, đặc biệt là khi câu hỏi không nêu rõ nó và những người đọc khác có thể được hưởng lợi từ một tuyên bố khẳng định hoặc phủ định.
mí mắt.

Chrome hiện có vẻ hỗ trợ nó.
Daniel X Moore

7

Trên thực tế, cách tiếp cận jquery không quá tệ. Xem:

http://docs.jquery.com/Events/error#fn

và:

$(window).error(function(msg, url, line){
  $.post("js_error_log.php", { msg: msg, url: url, line: line });
});

11
đối với bất kỳ ai tìm thấy điều này ngay bây giờ - jquery thực sự khuyên bạn không nên ràng buộc một sự kiện với sự kiện window.error - hãy xem liên kết tài liệu ở trên. Giải nén: Một trình xử lý sự kiện lỗi jQuery không nên được đính kèm vào đối tượng cửa sổ. [...] Sử dụng window.onerror để thay thế.
zcrar70,

ofc nó không nên bị ràng buộc theo cách này, nó phi logic! nhiều lỗi có thể xảy ra vào thời điểm đấu thầu này đã được thực hiện (nếu nó thậm chí còn thực hiện thành công ...)
vsync

6

Nắm bắt tất cả các ngoại lệ với trình xử lý ngoại lệ của riêng bạn và sử dụng instanceof.

$("inuput").live({
    click : function (event) {
        try {
            if (somethingGoesWrong) {
                throw new MyException();
            }
        } catch (Exception) {
            new MyExceptionHandler(Exception);
        }

    }
});

function MyExceptionHandler(Exception) {
    if (Exception instanceof TypeError || 
        Exception instanceof ReferenceError || 
        Exception instanceof RangeError ||  
        Exception instanceof SyntaxError ||     
        Exception instanceof URIError ) {
        throw Exception; // native error
     } else {
         // handle exception
     }
}

MyExcetpionHandler sẽ tạo ra lỗi gốc vì không có khối try-catch.

Truy cập http://www.nczonline.net/blog/2009/03/10/the-art-of-throwing-javascript-errors-part-2/


4

try-catchkhông phải lúc nào cũng là giải pháp tốt nhất. Ví dụ: trong Chrome 7.0, bạn mất dấu vết ngăn xếp đẹp mắt trong cửa sổ bảng điều khiển. Lùi lại ngoại lệ không giúp ích gì. Tôi không biết bất kỳ giải pháp nào lưu giữ dấu vết ngăn xếp cho phép bạn phản ứng trong trường hợp ngoại lệ.


2

Với một chút công việc, bạn có thể có được các đường xếp chồng hoàn chỉnh hợp lý trong tất cả các trình duyệt.

Chrome và Opera hiện đại (tức là bất kỳ thứ gì dựa trên công cụ kết xuất Blink) hỗ trợ đầy đủ thông số kỹ thuật bản nháp HTML 5 cho ErrorEvent và window.onerror. Trong cả hai trình duyệt này, bạn có thể sử dụng window.onerrorhoặc (thật tuyệt vời!) Liên kết đúng với sự kiện 'error':

// Only Chrome & Opera pass the error object.
window.onerror = function (message, file, line, col, error) {
    console.log(message, "from", error.stack);
    // You can send data to your server
    // sendData(data);
};
// Only Chrome & Opera have an error attribute on the event.
window.addEventListener("error", function (e) {
    console.log(e.error.message, "from", e.error.stack);
    // You can send data to your server
    // sendData(data);
})

Thật không may, Firefox, Safari và IE vẫn còn tồn tại và chúng tôi cũng phải hỗ trợ chúng. Vì stacktrace không khả dụng trongwindow.onerror chúng tôi phải làm thêm một chút công việc.

Nó chỉ ra rằng điều duy nhất chúng ta có thể làm để thoát khỏi lỗi là gói tất cả mã của chúng ta trong một try{ }catch(e){ }khối và sau đó xem xét e.stack. Chúng ta có thể làm cho quá trình dễ dàng hơn với một hàm có tên là wrap lấy một hàm và trả về một hàm mới với khả năng xử lý lỗi tốt.

function wrap(func) {
    // Ensure we only wrap the function once.
    if (!func._wrapped) {
        func._wrapped = function () {
            try{
                func.apply(this, arguments);
            } catch(e) {
                console.log(e.message, "from", e.stack);
                // You can send data to your server
                // sendData(data);
                throw e;
            }
        }
    }
    return func._wrapped;
};

Những công việc này. Bất kỳ chức năng nào bạn quấn thủ công sẽ có khả năng xử lý lỗi tốt.

Bạn có thể gửi dữ liệu bằng thẻ hình ảnh như sau

function sendData(data) {
    var img = newImage(),
        src = http://yourserver.com/jserror + '&data=' + encodeURIComponent(JSON.stringify(data));

    img.crossOrigin = 'anonymous';
    img.onload = function success() {
        console.log('success', data);
    };
    img.onerror = img.onabort = function failure() {
        console.error('failure', data);
    };
    img.src = src;
}

Tuy nhiên, bạn phải làm phần phụ trợ để thu thập dữ liệu và giao diện người dùng để trực quan hóa dữ liệu.

Tại Atatus , chúng tôi đang nỗ lực giải quyết vấn đề này. Không chỉ là theo dõi lỗi, Atatus cung cấp khả năng giám sát người dùng thực.

Hãy thử https://www.atatus.com/

Tuyên bố từ chối trách nhiệm: Tôi là nhà phát triển web tại Atatus.


1

Đúng là với các trình duyệt hiện đại, việc nối window.onerror đối với các lỗi nổi lên trên cùng cùng với việc thêm trình xử lý sự kiện jQuery cho các lỗi Ajax sẽ thực tế bắt được tất cả các đối tượng lỗi được đưa vào mã máy khách của bạn. Nếu bạn đang thiết lập thủ công một trình xử lý cho window.onerror, trong các trình duyệt hiện đại, điều này được thực hiện với window.addEventListener('error', callback), trong khi trong IE8 / 9, bạn cần gọi window.attachEvent('onerror', callback).

Lưu ý rằng sau đó bạn nên xem xét môi trường mà những lỗi này đang được xử lý và lý do để làm như vậy. Việc phát hiện càng nhiều lỗi càng tốt với các hệ thống ngăn xếp của chúng là một điều, nhưng sự ra đời của các công cụ phát triển F12 hiện đại giải quyết trường hợp sử dụng này khi triển khai và gỡ lỗi cục bộ. Các điểm ngắt, v.v. sẽ cung cấp cho bạn nhiều dữ liệu hơn số dữ liệu có sẵn từ trình xử lý, đặc biệt là đối với các lỗi do thư viện bên thứ ba đưa ra từ các yêu cầu CORS. Bạn cần thực hiện các bước bổ sung để hướng dẫn trình duyệt cung cấp dữ liệu này.

Vấn đề quan trọng là cung cấp dữ liệu này trong quá trình sản xuất, vì người dùng của bạn được đảm bảo chạy một loạt các trình duyệt và phiên bản rộng hơn nhiều so với mức bạn có thể thử nghiệm và trang web / ứng dụng của bạn sẽ bị hỏng theo những cách không mong muốn, cho dù bạn có ném vào bao nhiêu QA nó.

Để xử lý điều này, bạn cần một trình theo dõi lỗi sản xuất sẽ chọn mọi lỗi được đưa ra trong trình duyệt của người dùng khi họ sử dụng mã của bạn và gửi chúng đến một điểm cuối nơi bạn có thể xem dữ liệu và sử dụng để sửa lỗi khi chúng xảy ra . Tại Raygun (tuyên bố từ chối trách nhiệm: Tôi làm việc tại Raygun), chúng tôi đã nỗ lực rất nhiều để cung cấp trải nghiệm tuyệt vời cho việc này, vì có nhiều cạm bẫy và vấn đề cần xem xét mà một triển khai ngây thơ sẽ bỏ lỡ.

Ví dụ: rất có thể bạn sẽ gộp và giảm thiểu nội dung JS của mình, điều đó có nghĩa là các lỗi được tạo ra từ mã được rút gọn sẽ có các đường xếp chồng rác với các tên biến bị xáo trộn. Đối với điều này, bạn cần công cụ xây dựng của mình để tạo bản đồ nguồn (chúng tôi khuyên bạn nên sử dụng UglifyJS2 cho phần này của đường dẫn) và trình theo dõi lỗi của bạn để chấp nhận và xử lý chúng, biến các đường xếp chồng bị xáo trộn trở lại thành những đường có thể đọc được. Raygun thực hiện tất cả những điều này và bao gồm một điểm cuối API để chấp nhận bản đồ nguồn khi chúng được tạo ra bởi quá trình xây dựng của bạn. Đây là chìa khóa vì chúng cần được giữ ở chế độ không công khai, nếu không, bất kỳ ai cũng có thể phá hoại mã của bạn, phủ nhận mục đích của nó.

Các raygun4js thư viện client cũng đi kèm với window.onerrorcho cả các trình duyệt hiện đại và di sản, cũng như jQuery móc out-of-the-box, vì vậy để thiết lập này bạn chỉ cần thêm:

<script type="text/javascript" src="//cdn.raygun.io/raygun4js/raygun.min.js" </script> <script> Raygun.init('yourApiKey').attach(); </script>

Ngoài ra còn có một loạt chức năng được tích hợp bao gồm khả năng thay đổi trọng tải lỗi trước khi nó được gửi đi, thêm thẻ và dữ liệu tùy chỉnh, siêu dữ liệu về người dùng đã gặp lỗi. Nó cũng giúp bạn không phải lo lắng khi nhận được dấu vết ngăn xếp tốt từ các tập lệnh CORS bên thứ ba nói trên, giải quyết 'Lỗi Tập lệnh' đáng sợ (không chứa thông báo lỗi và không có dấu vết ngăn xếp).

Một vấn đề quan trọng hơn là do lượng người xem lớn trên web, trang web của bạn sẽ tạo ra hàng nghìn trường hợp trùng lặp của mỗi lỗi. Một dịch vụ theo dõi lỗi như Raygun có các tính năng thông minh để tổng hợp những lỗi này thành các nhóm lỗi để bạn không bị chìm trong đống thông báo và cho phép bạn xem từng lỗi thực tế đã sẵn sàng để sửa.


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.