Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doc: more use-cases for promise events #3438

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 32 additions & 9 deletions doc/api/process.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -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!'));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This patten is confusing to me. How does data actually get there once loaded?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not shown a complete implementation of SomeResource. I could do so if it would help. Essentially there's a SomeResource.prototype.load() method that will replace the promise with a successful one.

The idea is that anyone doing .loaded.then(...) before anything is loaded goes down the error path. Whereas, after something is loaded, they go down the success path.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fleshed this out in full painful detail https://gist.github.com/domenic/854f0dc0f698a63b0e8a. I think including all that would be way too much for the docs, but if there's a way to make it clearer, I'm happy to do so.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense.

}

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

<!--type=event-->
Expand Down