Обробка винятків JavaScript


82

Який найкращий прийом для виявлення ВСІХ винятків, створених у JavaScript?

Очевидно, що найкраща техніка - використовувати спробу ... зловити. Але з асинхронними зворотними викликами тощо, це може бути складно.

Я знаю, що браузери IE та Gecko підтримують window.onerror, а як щодо Opera та Safari?

Ось купа тестових випадків, для яких я хотів би мати центральне рішення для обробки винятків:

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

Якщо ви думаєте про інші тестові кейси, згадайте їх. Деякі з цих випадків згадують метод ErrorHandler.handleError. Це лише рекомендована настанова при використанні try ... catch.


Просто тому, що зрозуміло, що ви не помітили коментарів до моєї відповіді: здається, ви прихилили мене за "заявлене у питанні", коли воно читається як запитання: "а як щодо Opera та Safari?" Я спеціально відповів на поставлене тут питання. WTF?
безвічність

1
У WebKit window.onerrorпроблема зникнення є проблемою з 2003 року , але, схоже, вона нарешті вирішується . Звичайно, Opera залишатиметься завзятою.
josh3736

FYI window.onerror відмінно працює в - Firefox 7.0.1 - IE 8 - Chrome 16 - Opera 11.60
Віталій Капліч

11
Не знаю, чому це було закрито. Проголосували за повторне відкриття.
ripper234

1
Погоджено, це корисне питання. Єдине, про що я можу придумати, це casperOne боявся, що замість цього це стане якоюсь дискусією про війну браузера?
Йорданія Рейтер,

Відповіді:


23

Якщо ви використовуєте бібліотеку, як jQuery, для призначення всіх ваших обробників подій, ви можете використовувати комбінацію window.onerrorта обтікання коду обробника подій jQuery та функцію готовості з функцією обробки помилок (див .: Відстеження помилок JavaScript: Чому window.onerror недостатньо ).

  • window.onerror: виявляє всі помилки в IE (і більшість помилок у Firefox), але нічого не робить у Safari та Opera.
  • Обробники подій jQuery: виявляє помилки події jQuery у всіх браузерах.
  • Функція jQuery ready: виявляє помилки ініціалізації у всіх браузерах.

Я вже прочитав статтю, яка не пропонує жодного рішення. Я не використовую jQuery, але мене турбує те, що ви маєте на увазі. Ви хочете сказати, що jQuery їсть винятки ?! Або вони просто надають функціонал ведення журналу (що корисно лише після того, як буде відповідено на моє початкове запитання)?
harley.333

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


1
Це все ще правда? Я щойно спробував onerrorпідхід до звичайної обробки в Safari + Chrome і, здається, працює належним чином.
Juri

Посилання, яке ви дали на те, чому "цього замало", є досить старою інформацією, і зараз це не так.
vsync

21

Здається, WebKit (Safari, Chrome тощо) підтримує onerror.

Оригінальна публікація: Наскільки мені відомо, WebKit / Safari не підтримує onerrorподію. Що проклятий сором.


19
Ні, це не так. Запитаний у питанні: "а як щодо Opera та Safari?"
безвічність

Як і в тому випадку, я спеціально відповів на питання, поставлене в повідомленні.
безвічність

8
Думаю, він мав на увазі "що [я роблю] щодо Opera та Safari [у яких немає window.onerror]?"
nickf

10
@nickf, можливо, але якщо так, то це дуже погано сформульовано, і моє тлумачення в гіршому випадку зрозуміле і в кращому випадку найімовірніше. Це досить бідна причина для людей , щоб голосувати моя відповідь вниз, особливо з урахуванням того, що питання НЕ стверджувати його, і інші читачі можуть отримати вигоду від позитивного або негативного затвердження.
безвічність

Здається, Chrome зараз це підтримує.
Даніель X Мур

7

Насправді підхід jquery не такий вже й поганий. Подивитися:

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

і:

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

11
для тих, хто знайшов це зараз - jquery насправді рекомендує не прив’язувати подію до події window.error - див. посилання на документацію вище. Витяг: обробник подій помилок jQuery не слід приєднувати до об'єкта вікна. [...] Замість цього використовуйте window.onerror.
zcrar70

часто це не повинно бути пов'язано таким чином, це нелогічно! багато
моментів

6

Вловлюйте всі винятки за допомогою власного обробника винятків і використовуйте 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 видасть власну помилку, оскільки немає блоку try-catch.

Відвідайте http://www.nczonline.net/blog/2009/03/10/the-art-of-throwing-javascript-errors-part-2/


4

try-catchне завжди є найкращим рішенням. Наприклад, у Chrome 7.0 ви втрачаєте приємний стек у вікні консолі. Повернення винятку не допомагає. Я не знаю жодного рішення, яке б зберігало сліди стека і дозволяло вам реагувати на виняток.


2

Трохи попрацювавши, можна отримати стеки, які є достатньо повноцінними у всіх браузерах.

Сучасні Chrome та Opera (тобто все, що базується на механізмі рендеринга Blink) повністю підтримують специфікацію проекту HTML 5 для ErrorEvent та window.onerror. В обох цих браузерах ви можете або використовувати window.onerror, або (дивовижно!) Правильно прив’язати до події „помилка“:

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

На жаль, Firefox, Safari та IE все ще існують, і ми також повинні їх підтримати. Оскільки стек-трас недоступний, window.onerrorнам доведеться виконати трохи більше роботи.

Виявляється, єдине, що ми можемо зробити, щоб отримати стек-траси від помилок, - це обернути весь наш код try{ }catch(e){ }блоком, а потім подивитися e.stack. Ми можемо дещо спростити процес за допомогою функції, яка називається wrap, яка приймає функцію і повертає нову функцію з хорошою обробкою помилок.

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

Це працює. Будь-яка функція, яку ви обертаєте вручну, матиме хорошу обробку помилок.

Ви можете надсилати дані за допомогою тегу зображення наступним чином

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

Однак вам потрібно зробити бекенд для збору даних та інтерфейс для візуалізації даних.

В Atatus ми працюємо над вирішенням цієї проблеми. Більше, ніж відстеження помилок, Atatus забезпечує реальний моніторинг користувачів.

Спробуйте https://www.atatus.com/

Застереження: Я веб-розробник в Atatus.


1

Це правда, що в сучасних браузерах, підключення window.onerror до помилок, що спливають аж до верху, разом із додаванням обробників подій jQuery для помилок Ajax, буде вловлювати практично всі об’єкти Error, вкинуті у ваш код клієнта. Якщо ви вручну налаштовуєте обробник для window.onerror, у сучасних браузерах це робиться за допомогою window.addEventListener('error', callback), тоді як в IE8 / 9 вам потрібно зателефонувати window.attachEvent('onerror', callback).

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

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

Щоб вирішити це, вам потрібен робочий відстежувач помилок, який фіксує кожну помилку, видану браузерами вашого користувача, оскільки вони використовують ваш код, і відправляє їх до кінцевої точки, де ви можете переглядати дані та використовувати їх для виправлення помилок, коли вони трапляються . У Raygun (відмова від відповідальності: я працюю в Raygun) ми доклали багато зусиль, щоб забезпечити для цього чудовий досвід, оскільки є багато підводних каменів та проблем, які слід врахувати, оскільки наївна реалізація буде упущена.

Наприклад, є ймовірність того, що ви об’єднаєте та зменшите свої JS-ресурси, а це означає, що помилки, викинуті із мініфікованого коду, матимуть сміттєві стеки зі спотвореними іменами змінних. Для цього вам потрібен ваш інструмент побудови для створення вихідних карт (ми рекомендуємо UglifyJS2 для цієї частини конвеєра), а ваш відстежувач помилок повинен приймати та обробляти їх, перетворюючи зіпсовані стеки назад у зручні для читання. Raygun робить все це нестандартно і включає кінцеву точку API для прийняття вихідних карт, оскільки вони створюються вашим процесом збірки. Це є ключовим фактором, оскільки їх потрібно залишати загальнодоступними, інакше будь-хто міг би видалити ваш код, заперечуючи його призначення.

Raygun4js клієнтська бібліотека також поставляється з window.onerrorдля сучасних і застарілих браузерів, а також JQuery перехоплює поза коробки, так щоб встановити це вам потрібно тільки додати:

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

Також є вбудована функціональність, включаючи можливість змінити корисне навантаження помилки перед її відправленням, додавши теги та власні дані, метадані про користувача, який побачив помилку. Це також позбавляє від отримання хороших слідів стека з вищезазначених сторонніх сценаріїв CORS, що вирішує страшну "Помилку сценарію" (яка не містить жодного повідомлення про помилку та трасування стека).

Більш важливим питанням є те, що через величезну аудиторію в Інтернеті ваш сайт генеруватиме багато тисяч повторюваних випадків кожної помилки. Сервіс відстеження помилок, такий як Raygun, має розумність об’єднати їх у групи помилок, щоб ви не потонули в потоці сповіщень, і дозволяє побачити кожну фактичну помилку, готову до виправлення.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.