阿里云主机折上折
  • 微信号
Current Site:Index > The new AggregateError object

The new AggregateError object

Author:Chuan Chen 阅读数:62288人阅读 分类: JavaScript

Background of the AggregateError Object

ECMAScript 12 (ES2021) introduced the AggregateError object to represent cases where multiple errors are wrapped into a single error. This feature is particularly useful for scenarios requiring the simultaneous throwing of multiple errors, such as when the Promise.any() method needs to report all rejection reasons when all promises are rejected.

Basic Usage of AggregateError

The AggregateError constructor takes two parameters: an array of errors and an optional message string. It creates a new AggregateError object containing all the provided errors.

const error1 = new Error('Error 1');
const error2 = new Error('Error 2');
const aggregate = new AggregateError([error1, error2], 'Multiple errors occurred');

console.log(aggregate.message); // "Multiple errors occurred"
console.log(aggregate.errors); // [Error: Error 1, Error: Error 2]
console.log(aggregate.errors[0].message); // "Error 1"

AggregateError and Promise.any()

Promise.any() is a new method introduced in ES2021. It takes an array of promises and returns the value of the first resolved promise. If all promises are rejected, it throws an AggregateError containing all rejection reasons.

const promise1 = Promise.reject(new Error('Failed 1'));
const promise2 = Promise.reject(new Error('Failed 2'));

Promise.any([promise1, promise2])
  .catch(aggregateError => {
    console.log(aggregateError instanceof AggregateError); // true
    console.log(aggregateError.errors.length); // 2
    console.log(aggregateError.errors[0].message); // "Failed 1"
    console.log(aggregateError.errors[1].message); // "Failed 2"
  });

Custom AggregateError

You can create custom subclasses of AggregateError to add additional functionality or properties.

class CustomAggregateError extends AggregateError {
  constructor(errors, message, extraInfo) {
    super(errors, message);
    this.extraInfo = extraInfo;
  }
  
  getErrorCount() {
    return this.errors.length;
  }
}

const errors = [new Error('E1'), new Error('E2')];
const customError = new CustomAggregateError(errors, 'Custom error', {code: 500});

console.log(customError.getErrorCount()); // 2
console.log(customError.extraInfo.code); // 500

Handling Errors with AggregateError

AggregateError is particularly useful when handling multiple operations that might fail. Here's an example of batch processing files:

async function processFiles(filePaths) {
  const errors = [];
  const results = [];
  
  for (const filePath of filePaths) {
    try {
      const content = await readFile(filePath);
      results.push(processContent(content));
    } catch (error) {
      errors.push(error);
    }
  }
  
  if (errors.length > 0) {
    throw new AggregateError(errors, `Failed to process ${errors.length} files`);
  }
  
  return results;
}

try {
  await processFiles(['file1.txt', 'file2.txt', 'file3.txt']);
} catch (error) {
  if (error instanceof AggregateError) {
    console.error(`Total errors: ${error.errors.length}`);
    error.errors.forEach((err, index) => {
      console.error(`Error ${index + 1}: ${err.message}`);
    });
  } else {
    console.error('Unexpected error:', error);
  }
}

Browser Compatibility of AggregateError

AggregateError is widely supported in modern browsers, including:

  • Chrome 85+
  • Firefox 79+
  • Safari 14+
  • Edge 85+
  • Node.js 15.0.0+

For unsupported environments, you can use a polyfill:

if (typeof AggregateError === 'undefined') {
  class AggregateError extends Error {
    constructor(errors, message) {
      super(message);
      this.errors = errors;
      this.name = 'AggregateError';
    }
  }
  globalThis.AggregateError = AggregateError;
}

Comparison of AggregateError with Other Error Types

Feature AggregateError Error TypeError
Can contain multiple errors Yes No No
Primarily used for Promise.any() Yes No No
Can be subclassed Yes Yes Yes
Browser support ES2021+ ES1 ES1

Practical Use Cases

  1. Batch API Requests: When making requests to multiple endpoints and collecting errors from all failed requests.
async function fetchMultipleUrls(urls) {
  const promises = urls.map(url => 
    fetch(url).catch(error => error)
  );
  const results = await Promise.all(promises);
  
  const errors = results.filter(result => result instanceof Error);
  if (errors.length > 0) {
    throw new AggregateError(errors, 'Some requests failed');
  }
  
  return results;
}
  1. Form Validation: Collecting validation errors for all fields in a form.
function validateForm(formData) {
  const errors = [];
  
  if (!formData.username) {
    errors.push(new Error('Username is required'));
  }
  
  if (formData.password.length < 8) {
    errors.push(new Error('Password must be at least 8 characters'));
  }
  
  if (errors.length > 0) {
    throw new AggregateError(errors, 'Form validation failed');
  }
}
  1. Database Transactions: Recording all operation failures when rolling back a transaction.
async function executeTransaction(operations) {
  const errors = [];
  
  try {
    await beginTransaction();
    
    for (const op of operations) {
      try {
        await executeOperation(op);
      } catch (error) {
        errors.push(error);
      }
    }
    
    if (errors.length > 0) {
      await rollbackTransaction();
      throw new AggregateError(errors, 'Transaction failed');
    }
    
    await commitTransaction();
  } catch (error) {
    if (!(error instanceof AggregateError)) {
      await rollbackTransaction();
      throw error;
    }
  }
}

Best Practices for AggregateError

  1. Error Messages: Provide meaningful aggregated error messages while preserving the original messages of individual errors.
  2. Error Count: Check the length of the errors array when handling an AggregateError.
  3. Error Types: Preserve the original error types; avoid converting all errors to generic Error objects.
  4. Logging: When logging an AggregateError, ensure all sub-errors are logged.
  5. Error Propagation: In middleware or high-level error handling, consider whether to split the AggregateError into individual errors.
// Good error handling example
try {
  await someOperationThatMightThrowAggregateError();
} catch (error) {
  if (error instanceof AggregateError) {
    logger.error(`Operation failed with ${error.errors.length} errors:`);
    error.errors.forEach((err, index) => {
      logger.error(`Error ${index + 1}:`, err.stack || err.message);
    });
    
    // Decide whether to handle all errors or rethrow based on business needs
    if (error.errors.some(err => err instanceof CriticalError)) {
      throw error.errors.find(err => err instanceof CriticalError);
    }
  } else {
    logger.error('Unexpected error:', error);
    throw error;
  }
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:顶级await

下一篇:类静态块

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.