Jak sprawdzić, które obietnice nie są obsługiwane w Node.js UnhandledPromiseRejectionWarning?

177

Node.js od wersji 7 ma cukier składniowy async / await do obsługi obietnic, a teraz w moim kodzie dość często pojawia się następujące ostrzeżenie:

(node:11057) UnhandledPromiseRejectionWarning: Unhandled promise 
rejection (rejection id: 1): ReferenceError: Error: Can't set headers 
after they are sent.
(node:11057) DeprecationWarning: Unhandled promise rejections are 
deprecated. In the future, promise rejections that are not handled 
will terminate the Node.js process with a non-zero exit code.

Niestety nie ma odniesienia do wiersza, w którym brakuje haczyka. Czy jest sposób, aby go znaleźć bez sprawdzania każdego bloku try / catch?

user1658162
źródło
Możesz użyć biblioteki obietnic Bluebird i prawdopodobnie da ci to ślad stosu.
jfriend00
3
Może unhandledRejectionpomoże Ci rejestracja na wydarzenie Node ? Zobacz dokumentację . Twoje wywołanie zwrotne pobiera Errorobiekt i rzeczywisty Promise, i uważam, że Errorobiekt może zawierać ślad stosu.
YSK
Jeśli dwa poprzednie komentarze nie pomogą, to Can't set headers after they are sent.powinien dać ci wskazówkę, gdzie w twoim kodzie może się to dziać (tj. Gdzieś ustawiasz nagłówki po tym, jak nagłówki zostałyby już wysłane - prawdopodobnie z powodu braku zrozumienia kodu asynchronicznego , ale to przypuszczenie)
Jaromanda X
Cześć, wiadomości z pewnością pomagają znaleźć, gdzie w kodzie jest błąd, przy okazji nie jest to tak łatwe, jak znajomość linii.
user1658162
1
@ jfriend00 Okazuje się, że była to sytuacja, w której funkcja async generowała błąd - te wewnętrzne obietnice Node dotyczące funkcji asynchronicznych nigdy nie używają Bluebird, więc posiadanie Bluebird nie pomaga w tym scenariuszu.
Adam Reis

Odpowiedzi:

297

słuchać unhandledRejectionzdarzenia procesu.

process.on('unhandledRejection', (reason, p) => {
  console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
  // application specific logging, throwing an error, or other logic here
});
cuixiping
źródło
35
Rejestrowanie error.stack(lub w powyższym przykładzie reason.stack) daje pełny ślad stosu błędu.
Adam Reis
Dziękuję za umieszczenie, process.ona nie server.onjak w wielu innych przykładach, które znalazłem
PhillipHolmes,
9
Chciałbym móc powiedzieć, że to zadziałało, ale tak nie jest. Jestem na węźle 8.9.4.
ffxsam,
2
Wypróbowałem powyższy kod i otrzymałem undefined z obu powodów, a p? Jakieś sugestie? „Unhandled Rejection at: Promise {state: 'excluded', powód: undefined} powód: undefined”
Jeremy
3
Dodałem ten kod na początku mojego app.jspliku węzłów i niestety nic nie jest rejestrowane. Node v10.13.0.
user1063287
71

Poprawny sposób, aby pokazać pełny StackTrace dla nieobsługiwany odrzucenia ES6 obietnica jest uruchomienie node.js z --trace-warningsflagą. Spowoduje to wyświetlenie pełnego śladu stosu dla każdego ostrzeżenia, bez konieczności przechwytywania odrzucenia z własnego kodu. Na przykład:

node --trace-warnings app.js

Upewnij się, że trace-warningsflaga znajduje się przed nazwą .jspliku! W przeciwnym razie flaga zostanie zinterpretowana jako argument twojego skryptu i zostanie zignorowana przez sam Node.js.

Jeśli chcesz faktycznie obsłużyć nieobsłużone odrzuty (np. Przez rejestrowanie ich), możesz unhandled-rejectionzamiast tego użyć mojego modułu, który przechwytuje wszystkie nieobsłużone odrzuty dla każdej głównej implementacji Promises, która go obsługuje, z pojedynczą obsługą zdarzenia.

Tego modułu podpory Bluebird obiecuje ES6, Q, WhenJS, es6-promise, then/promise, i nic, które odpowiada żadnej z nieobsłużonych specyfikacji odrzuceniu (pełne szczegóły w dokumentacji).

Sven Slootweg
źródło
20
Korzystanie z węzła 7.8.0 i wszystko to daje mi ślad stosu dla kilku wewnętrznych modułów węzłów. (węzeł: 10372) UnhandledPromiseRejectionWarning: Unhandled promise odrzucenie (identyfikator odrzucenia: 2): undefined at emitWarning (internal / process / promises.js: 59: 21) at emitPendingUnhandledRejections (internal / process / promises.js: 86: 11) w procesie ._tickDomainCallback (internal / process / next_tick.js: 136: 7)
Will Lovett
3
Nie widzę żadnych danych wyjściowych pokazujących, gdzie jest nieobsłużony problem z obietnicą.
Jason Leach,
Dodałem to, aby package.jsonuruchomić skrypt i niestety nic nie zostało zapisane. Node v10.13.0.
user1063287
1
@ user1063287 Upewnij się, że flaga znajduje się we właściwym miejscu w poleceniu. Właśnie dodałem aktualizację do odpowiedzi, aby podkreślić, że musi ona znajdować się przed nazwą skryptu.
Sven Slootweg
2
Prawdopodobnie patrzysz na ślad stosu ostrzeżenia o wycofaniu, a nie na pierwotny nieobsłużony błąd (który powinien znajdować się gdzieś powyżej ostrzeżenia o wycofaniu).
Sven Slootweg
7

Rejestrowanie za pomocą śladu stosu

Jeśli szukasz bardziej pomocnego komunikatu o błędzie. Spróbuj dodać to do pliku węzłów. Powinien wyświetlić pełny ślad stosu, w którym ma miejsce twoja awaria.

process.on('unhandledRejection', (error, p) => {
  console.log('=== UNHANDLED REJECTION ===');
  console.dir(error.stack);
});
joshuakcockrell
źródło
Jedyną różnicą funkcjonalną jest wykonanie console.dir na właściwości stosu błędu. Spora różnica w wydajności w porównaniu z przyjętą odpowiedzią.
joshuakcockrell