Skip to content

Latest commit

 

History

History
138 lines (94 loc) · 6.11 KB

debug-api.md

File metadata and controls

138 lines (94 loc) · 6.11 KB

Debug APIs

NOTE: This document describes APIs that provide support to external debugging tools. Do not use these APIs in normal application logic. For info and help on debugging promises in your application, see Debugging Promises.

These APIs allow debugging tools to receive information about promise errors. For example, when.js's default builtin unhandled rejection reporting is built using these APIs, as is the long async stack trace support in when/monitor/console.

A debugger could use them to do any number of things, such as display a list of "currently unhandled promise rejections", or send error reports to an error aggregation service.

Global rejection events

when.js >= 3.7.0 supports global window events in browsers, and process events in Node, similar to Node's 'uncaughtException' event. This allows applications to register a handler to receive events from all promise implementations that support these global events.

The events are:

  • 'unhandledRejection': fired when an unhandled rejection is detected
  • 'rejectionHandled': fired when rejection previously reported via an 'unhandledRejection' event becomes handled

Browser window events

The following example shows how to use global window events in browsers to implement simple debug output. The event object has the following extra properties:

  • event.detail.reason - the rejection reason (typically an Error instance)
  • event.detail.key - opaque unique key representing the promise that was rejected. This key can be used to correlate corresponding unhandledRejection and rejectionHandled events for the same promise.
window.addEventListener('unhandledRejection', function(event) {
	// Calling preventDefault() suppresses when.js's default rejection logging
	// in favor of your own.
	event.preventDefault();
	reportRejection(event.detail.reason, event.detail.key);
}, false);

window.addEventListener('rejectionHandled', function(event) {
	// Calling preventDefault() suppresses when.js's default rejection logging
	// in favor of your own.
	event.preventDefault();
	reportHandled(event.detail.key);
}, false);

function reportRejection(error, key) {
	// Implement whatever logic your application requires
	// Log or record error state, etc.
}

function reportHandled(key) {
	// Implement whatever logic your application requires
	// Log that error has been handled, etc.
}

Node global process events

The following example shows how to use global process events in Node.js to implement simple debug output. The parameters passed to the process event handlers:

  • reason - the rejection reason (typically an Error instance)
  • key - opaque unique key representing the promise that was rejected. This key can be used to correlate corresponding unhandledRejection and rejectionHandled events for the same promise.
process.on('unhandledRejection', function(reason, key) {
	reportRejection(reason, key);
});

process.on('rejectionHandled', function(key) {
	reportHandled(key);
});

function reportRejection(error, key) {
	// Implement whatever logic your application requires
	// Log or record error state, etc.
}

function reportHandled(key) {
	// Implement whatever logic your application requires
	// Log that error has been handled, etc.
}

Local when.js instance API

Example

A good example is the default implementation in when/lib/decorators/unhandledRejection, which logs unhandled rejections to the console.

The following example shows how to combine Promise.onPotentiallyUnhandledRejection and Promise.onPotentiallyUnhandledRejectionHandled to implement a simple debug UI:

var Promise = require('when').Promise;

Promise.onPotentiallyUnhandledRejection = function(rejection) {
	addToDebugDisplay(rejection.id, rejection.value);
}

Promise.onPotentiallyUnhandledRejection = function(rejection) {
	removeFromDebugDisplay(rejection.id);
}

function addToDebugDisplay(id, error) {
	// Add to custom debug UI here
}

function removeFromDebugDisplay(id) {
	// Remove from custom debug UI here
}

Promise.onPotentiallyUnhandledRejection

Called for each rejected promise that appears not to have been handled. A rejection descriptor is provided as the argument:

{
	id: <unique id of the rejection>
	value: <the rejection's reason>
	handled: <boolean indicating if this rejection has been handled>
	// may contain other, internal/bookkeeping fields
}

Technically, this is called after the internal task queue has been flushed, for each rejected promise that hasn't yet been observed, for example by calling its .then or .catch methods.

The handled flag is useful if your implementation of onPotentiallyUnhandledRejection uses setTimeout or another technique to delay reporting, since the rejection may be handled between the instant you call setTimeout and the instant the timeout function executes. IOW, if you use setTimeout, you should check handled to verify that the rejection is still unhandled.

The default implementation in when/lib/decorators/unhandledRejection logs error information to console.error that includes the id.

Promise.onPotentiallyUnhandledRejectionHandled

Called when a rejection previously passed to Promise.onPotentiallyUnhandledRejection becomes handled, for example if it is observed later by calling its .then or .catch methods.

It is passed the same rejection descriptor object as Promise.onPotentiallyUnhandledRejection. The handled field will always be true when a descriptor is passed to onPotentiallyUnhandledRejectionHandled.

The default implementation in when/lib/decorators/unhandledRejection logs an additional message to console.log with the id indicating that the rejection has been handled.

Promise.onFatalRejection

Called when an error propagates out of a terminal promise.done, for example, if a callback passed to promise.done throws an exception.

The default implementation in when/lib/decorators/unhandledRejection throws an uncatchable exception that will be logged to console.error by browsers and will halt (crash) Node.js.