Novinka v JavaScriptu:reportError – metoda hlášení globálním obslužným rutinám událostí

Pokud jste autor knihoven, vždy vyvstává otázka, jak implementovat snadno použitelné zpracování chyb. Chcete se ujistit, že váš kód je neprůstřelný a nevybuchne v případě výjimky, ale chcete zajistit, aby se chyby dostaly až ke koncovému uživateli a také ke sledování jejich chyb.

Jak to tedy uděláte?

Sledování chyb frontendu je obvykle založeno na obslužné rutině globální chybové události, která se spouští v případě neošetřené výjimky.

window.onerror = function (message, source, lineno, colno, error) {
  console.log("Global error: " + error.message + ", lineno: " + lineno);
  return true;
};

// Tip: you could also use `addEventListener`
// -> window.addEventListener("error", ...)

function triggerError() {
  throw new Error('Oh no!');
}

triggerError();

// Console output:
// Global error: Oh no!, lineno: 10

Tento přístup funguje skvěle, ale zpracování chyb se komplikuje, pokud jste v zásobníku volání o několik úrovní hluboko.

Podívejme se na příklady a předstírejme, že píšete kód knihovny, který přijímá posluchače událostí, které nakonec iterujete.

Následující fragmenty kódu běží v prostředí, které definuje obslužnou rutinu globální chybové události, jako je ta výše (window.error = function () {} ) a zaznamenává nezachycené výjimky do konzole.

Nejprve iterujte předané obslužné rutiny událostí bez jakéhokoli zpracování chyb:

// Custom event handlers passed by someone else
const fns = [
  () => { console.log("I'm first!"); },
  () => { throw new Error("Oh no!"); },
  () => { console.log("I'm third!"); },
];

// Iterate over the functions
for (const fn of fns) {
  fn();
}

// Output in the console:
// I'm first!
// Global error: Oh no!, lineno: 10

Globální obslužný program chyb se spouští, aby uživatelé vaší knihovny mohli zpracovávat a monitorovat výjimky. To je skvělé, ale vyhozená výjimka vybuchne a zastaví smyčku také. Třetí funkce není spuštěna.

Pojďme přidat zpracování výjimek pomocí try/catch :

// Custom event handlers passed by some one else
const fns = [
  () => { console.log("I'm first!"); },
  () => { throw new Error("Oh no!"); },
  () => { console.log("I'm third!"); },
];

// Iterate over the methods
for (const fn of fns) {
  try {
    fn();
  } catch(error) {
    console.error(error);
  }
}

// Output in the console:
// I'm first!
// Error: Oh no!
// I'm third!

Smyčka je úspěšná s přidaným try/catch příkazu, ale chyba již neprobublává do obslužné rutiny globální události. Jak potom předáte výjimku v řetězci?

Existuje osvědčený způsob... 🙈

for (const fn of fns) {
  try {
    fn();
  } catch (error) {
    // Use setTimeout hack to trigger the global error
    setTimeout(() => {
      throw error;
    }, 0);
  }
}

// Console output:
// I'm first!
// I'm third!
// Global error: Oh no!, lineno: 24

A při používání setTimeout funguje, není to víc než hack.

Jak spouštět obslužné nástroje globálních chybových událostí bez hacků

Naštěstí je k dispozici nová metoda pro spuštění window.onerror nebo window.addEventListener('error', ...) . Pozdravte reportError . 👋

reportError() globální metodu lze použít k hlášení chyb konzole nebo obslužným rutinám globálních událostí, emulující nezachycenou JavaScriptovou výjimku.

Bez ohledu na to, jak hluboko jste ve své aplikaci a volání funkcí, reportError vám dává příležitost zpracovat výjimky po svém, ale také spouštět globálně definované obslužné rutiny chyb .

for (const fn of fns) {
  try {
    fn();
  } catch (error) {
    // add custom error handling but also
    // trigger global error handlers
    reportError(error);
  }
}

// Console output:
// I'm first!
// Global error: Oh no!, lineno: 24
// I'm third!

A nejlepší věc:pokud jde o podporu napříč prohlížeči, jsme téměř tam!

MDN Compat Data (zdroj)
Informace o podpoře prohlížeče pro reportError
95 95 95 93 93 15.4 15.4 17,0 95

Ale mějte na paměti, i když reportError bude brzy podporována napříč prohlížeči, aby bylo možné detekovat její dostupnost a polyfill metodu. Jak nedávno zdůraznil Eric Bailey, ""Evergreen" neznamená, že je okamžitě k dispozici."

Pokud hledáte další informace o reportError podívejte se na následující zdroje:

  • reportError na MDN
  • Přidání PR reportError na specifikaci WHATWG
  • Stará, ale zajímavá diskuze o esdiscuss.org