CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-promise

Bare bones Promises/A+ implementation with essential extensions for readable, performant asynchronous operation handling.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

rejection-tracking.mddocs/

Rejection Tracking

Development utilities for tracking and debugging unhandled promise rejections. Helps identify potential memory leaks and uncaught errors in promise chains.

Capabilities

enable

Enables unhandled rejection tracking with configurable options.

/**
 * Enables unhandled rejection tracking
 * @param {Object} [options] - Configuration options
 * @param {boolean} [options.allRejections=false] - Track all rejections, not just reference/type errors
 * @param {Array<ErrorConstructor>} [options.whitelist] - Error types to track (default: [ReferenceError, TypeError, RangeError])
 * @param {function} [options.onUnhandled] - Custom handler for unhandled rejections
 * @param {function} [options.onHandled] - Custom handler for subsequently handled rejections
 * @returns {void}
 */
const rejectionTracking = require('promise/lib/rejection-tracking');
rejectionTracking.enable(options);

Usage Examples:

const rejectionTracking = require('promise/lib/rejection-tracking');

// Basic tracking (default: only ReferenceError and TypeError)
rejectionTracking.enable();

// Track all rejections (warning: may have false positives)
rejectionTracking.enable({
  allRejections: true
});

// Custom error tracking
rejectionTracking.enable({
  whitelist: [TypeError, ReferenceError, RangeError]
});

// Custom handlers
rejectionTracking.enable({
  onUnhandled: (id, error) => {
    console.error(`Unhandled rejection #${id}:`, error);
    // Log to monitoring service
    logToService('unhandled-rejection', { id, error: error.stack });
  },
  onHandled: (id, error) => {
    console.warn(`Previously unhandled rejection #${id} was handled:`, error.message);
  }
});

disable

Disables unhandled rejection tracking.

/**
 * Disables unhandled rejection tracking
 * @returns {void}
 */
rejectionTracking.disable();

Usage Examples:

const rejectionTracking = require('promise/lib/rejection-tracking');

// Enable tracking
rejectionTracking.enable();

// ... application code ...

// Disable tracking (e.g., for production)
rejectionTracking.disable();

Configuration Options

allRejections

When true, tracks all promise rejections regardless of error type. Use with caution as it may produce false positives.

const rejectionTracking = require('promise/lib/rejection-tracking');

// Track everything - useful for debugging specific issues
rejectionTracking.enable({
  allRejections: true
});

// Example: This will be tracked even though it might be intentional
fetch('/api/data')
  .catch(error => {
    // Handled, but was briefly unhandled
    handleNetworkError(error);
  });

whitelist

Array of error constructors to track. Defaults to [ReferenceError, TypeError, RangeError].

const rejectionTracking = require('promise/lib/rejection-tracking');

// Custom error types to track
rejectionTracking.enable({
  whitelist: [
    ReferenceError,  // Default
    TypeError,       // Default  
    RangeError,      // Default
    SyntaxError,     // Custom addition
    CustomError      // Custom addition
  ]
});

class CustomError extends Error {
  constructor(message) {
    super(message);
    this.name = 'CustomError';
  }
}

Custom Handlers

Provide custom functions to handle unhandled and subsequently handled rejections.

const rejectionTracking = require('promise/lib/rejection-tracking');

rejectionTracking.enable({
  onUnhandled: (id, error) => {
    // Custom logging
    const timestamp = new Date().toISOString();
    console.error(`[${timestamp}] Unhandled Promise Rejection #${id}`);
    console.error('Error:', error.stack);
    
    // Send to monitoring service
    if (process.env.NODE_ENV === 'production') {
      sendToMonitoring({
        type: 'unhandled-promise-rejection',
        id,
        error: error.message,
        stack: error.stack,
        timestamp
      });
    }
  },
  
  onHandled: (id, error) => {
    console.warn(`Promise rejection #${id} was handled after being logged`);
    console.warn('This indicates the error handler was attached too late');
  }
});

Timing and Behavior

Detection Delays

  • ReferenceError/TypeError: 100ms delay (likely programmer errors)
  • Other errors: 2000ms delay (might be handled later)
const rejectionTracking = require('promise/lib/rejection-tracking');

rejectionTracking.enable();

// This will be logged after 100ms if not handled
Promise.reject(new TypeError('Undefined variable'));

// This will be logged after 2000ms if not handled  
Promise.reject(new Error('Network timeout'));

// This won't be logged (handled within delay)
Promise.reject(new Error('Will be handled'))
  .catch(error => console.log('Handled:', error.message));

Late Handling Detection

The system can detect when a rejection is handled after being logged as unhandled.

const rejectionTracking = require('promise/lib/rejection-tracking');

rejectionTracking.enable();

const promise = Promise.reject(new Error('Late handling test'));

// After 2+ seconds, attach handler
setTimeout(() => {
  promise.catch(error => {
    console.log('Finally handled:', error.message);
    // This will trigger onHandled callback
  });
}, 3000);

Development Patterns

Development vs Production

const rejectionTracking = require('promise/lib/rejection-tracking');

if (process.env.NODE_ENV === 'development') {
  // Aggressive tracking in development
  rejectionTracking.enable({
    allRejections: true,
    onUnhandled: (id, error) => {
      console.error('🚨 Unhandled Promise Rejection:', error);
      console.trace(); // Show stack trace
    }
  });
} else if (process.env.NODE_ENV === 'staging') {
  // Conservative tracking in staging
  rejectionTracking.enable({
    onUnhandled: (id, error) => {
      logToService('unhandled-rejection', { id, error: error.stack });
    }
  });
}
// Disabled in production

Testing Integration

const rejectionTracking = require('promise/lib/rejection-tracking');

// For testing - track all rejections
function enableTestingMode() {
  const unhandledRejections = [];
  
  rejectionTracking.enable({
    allRejections: true,
    onUnhandled: (id, error) => {
      unhandledRejections.push({ id, error });
    }
  });
  
  return {
    getUnhandledRejections: () => unhandledRejections.slice(),
    clearUnhandledRejections: () => unhandledRejections.splice(0),
    disable: () => rejectionTracking.disable()
  };
}

// Usage in tests
const tracker = enableTestingMode();

// Run test code...

const unhandled = tracker.getUnhandledRejections();
if (unhandled.length > 0) {
  console.warn('Test produced unhandled rejections:', unhandled);
}

tracker.disable();

Common Use Cases

Memory Leak Detection

const rejectionTracking = require('promise/lib/rejection-tracking');

rejectionTracking.enable({
  allRejections: true,
  onUnhandled: (id, error) => {
    console.error(`Potential memory leak - unhandled rejection #${id}`);
    console.error('Error:', error.message);
    
    // In production, you might want to:
    // - Log to monitoring service
    // - Increment metrics counter
    // - Alert development team
  }
});

API Error Monitoring

const rejectionTracking = require('promise/lib/rejection-tracking');

rejectionTracking.enable({
  onUnhandled: (id, error) => {
    // Check if it's an API-related error
    if (error.message.includes('fetch') || error.code === 'NETWORK_ERROR') {
      console.error(`Unhandled API error #${id}:`, error.message);
      
      // Track API reliability metrics
      incrementMetric('api.unhandled_errors');
    }
  }
});

Types

/**
 * Options for enabling rejection tracking
 */
interface RejectionTrackingOptions {
  /** Track all rejections, not just reference/type errors */
  allRejections?: boolean;
  
  /** Error constructors to track (default: [ReferenceError, TypeError, RangeError]) */
  whitelist?: ErrorConstructor[];
  
  /** Custom handler for unhandled rejections */
  onUnhandled?: (id: number, error: any) => void;
  
  /** Custom handler for subsequently handled rejections */
  onHandled?: (id: number, error: any) => void;
}

Install with Tessl CLI

npx tessl i tessl/npm-promise

docs

core-promise.md

es6-static-methods.md

extension-methods.md

index.md

nodejs-integration.md

rejection-tracking.md

synchronous-inspection.md

tile.json