From d38129085445563818c3527d2fbe75fd8e7b01b3 Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Thu, 26 Feb 2015 18:17:15 -0500 Subject: [PATCH] doc: more use-cases for promise events This adds an example of a semi-common promise pattern that could result in false-positive 'unhandledRejection' events, to help motivate why there is a dual 'rejectionHandled' event. I anticipate it being helpful to users who encounter 'unhandledRejection' events that do not stem from obvious typos such as the JSON.pasre example. Also cleans up the promise rejection tracking sample. By using a Map instead of array we can get O(1) deletion and actually record the errors. And, fixed indentation and backtick usage there to align with the rest of the document. Reviewed-By: Stephan Belanger Reviewed-By: Petka Antonov Reviewed-By: James M Snell PR-URL: https://github.com/nodejs/node/pull/3438 --- doc/api/process.markdown | 41 +++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/doc/api/process.markdown b/doc/api/process.markdown index 71953766d339aa..eecf494c48bf27 100644 --- a/doc/api/process.markdown +++ b/doc/api/process.markdown @@ -159,40 +159,63 @@ event: return reportToUser(JSON.pasre(res)); // note the typo }); // no `.catch` or `.then` +Here is an example of a coding pattern that will also trigger +`'unhandledRejection'`: + + function SomeResource() { + // Initially set the loaded status to a rejected promise + this.loaded = Promise.reject(new Error('Resource not yet loaded!')); + } + + var resource = new SomeResource(); + // no .catch or .then on resource.loaded for at least a turn + +In cases like this, you may not want to track the rejection as a developer +error like you would for other `'unhandledRejection'` events. To address +this, you can either attach a dummy `.catch(function() { })` handler to +`resource.loaded`, preventing the `'unhandledRejection'` event from being +emitted, or you can use the `'rejectionHandled'` event. Below is an +explanation of how to do that. + ## Event: 'rejectionHandled' Emitted whenever a Promise was rejected and an error handler was attached to it (for example with `.catch()`) later than after an event loop turn. This event is emitted with the following arguments: - - `p` the promise that was previously emitted in an 'unhandledRejection' + - `p` the promise that was previously emitted in an `'unhandledRejection'` event, but which has now gained a rejection handler. There is no notion of a top level for a promise chain at which rejections can always be handled. Being inherently asynchronous in nature, a promise rejection can be be handled at a future point in time — possibly much later than the -event loop turn it takes for the 'unhandledRejection' event to be emitted. +event loop turn it takes for the `'unhandledRejection'` event to be emitted. Another way of stating this is that, unlike in synchronous code where there is an ever-growing list of unhandled exceptions, with promises there is a growing-and-shrinking list of unhandled rejections. In synchronous code, the 'uncaughtException' event tells you when the list of unhandled exceptions -grows. And in asynchronous code, the 'unhandledRejection' event tells you +grows. And in asynchronous code, the `'unhandledRejection'` event tells you when the list of unhandled rejections grows, while the 'rejectionHandled' event tells you when the list of unhandled rejections shrinks. -For example using the rejection detection hooks in order to keep a list of all -the rejected promises at a given time: +For example using the rejection detection hooks in order to keep a map of all +the rejected promise reasons at a given time: - var unhandledRejections = []; + var unhandledRejections = new Map(); process.on('unhandledRejection', function(reason, p) { - unhandledRejections.push(p); + unhandledRejections.set(p, reason); }); process.on('rejectionHandled', function(p) { - var index = unhandledRejections.indexOf(p); - unhandledRejections.splice(index, 1); + unhandledRejections.delete(p); }); +This map will grow and shrink over time, reflecting rejections that start +unhandled and then become handled. You could record the errors in some error +log, either periodically (probably best for long-running programs, allowing +you to clear the map, which in the case of a very buggy program could grow +indefinitely) or upon process exit (more convenient for scripts). + ## Signal Events