手写一个具备‘聚合功能’的 `AggregateError`:处理多个并行 Promise 失败的场景

技术讲座:聚合错误处理——并行Promise失败场景下的解决方案

引言

在异步编程中,Promise 是一种常用的处理异步操作的工具。然而,当多个 Promise 同时执行时,可能会遇到一些问题,比如某些 Promise 失败了,但其他 Promise 仍在继续执行。这种情况下,如何有效地处理这些错误,并聚合它们的信息,是一个值得探讨的问题。本文将深入探讨如何实现一个具备聚合功能的 AggregateError,以处理多个并行 Promise 失败的场景。

一、Promise 与错误处理

1.1 Promise 的基本概念

Promise 是一个表示异步操作最终完成或失败的对象。它有三个状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。Promise 对象提供了一系列方法,如 .then().catch().finally(),用于处理异步操作的结果。

1.2 错误处理

在异步编程中,错误处理是一个重要的环节。Promise 提供了 .catch() 方法用于处理异步操作中发生的错误。然而,当多个 Promise 同时执行时,如何处理这些错误呢?

二、聚合错误处理

2.1 聚合错误处理的概念

聚合错误处理是指将多个异步操作中发生的错误信息进行整合,以形成一个更全面的错误信息。这样,开发者可以更方便地了解整个异步操作过程中的错误情况。

2.2 实现 AggregateError

下面以 Python 语言为例,实现一个具备聚合功能的 AggregateError

class AggregateError(Exception):
    def __init__(self, errors):
        super().__init__()
        self.errors = errors

    def __str__(self):
        return ', '.join(str(err) for err in self.errors)

2.3 使用 AggregateError

def promise1():
    return Promise.resolve("Success 1")

def promise2():
    return Promise.reject("Error 2")

def promise3():
    return Promise.reject("Error 3")

def aggregate_errors(promises):
    errors = []
    for p in promises:
        try:
            result = await p
            print(result)
        except Exception as e:
            errors.append(e)
    if errors:
        raise AggregateError(errors)

promises = [promise1(), promise2(), promise3()]
try:
    await aggregate_errors(promises)
except AggregateError as e:
    print(e)

三、工程级代码示例

3.1 PHP

class AggregateError extends Exception {
    private $errors;

    public function __construct($errors) {
        parent::__construct();
        $this->errors = $errors;
    }

    public function __toString() {
        return implode(", ", $this->errors);
    }
}

$promise1 = new Promise(function ($resolve, $reject) {
    $resolve("Success 1");
});

$promise2 = new Promise(function ($resolve, $reject) {
    $reject("Error 2");
});

$promise3 = new Promise(function ($resolve, $reject) {
    $reject("Error 3");
});

$promises = [$promise1, $promise2, $promise3];

try {
    foreach ($promises as $promise) {
        $result = $promise->then(function ($result) {
            echo $result . "n";
        }, function ($error) use ($promise) {
            throw new AggregateError([$promise, $error]);
        });
    }
} catch (AggregateError $e) {
    echo $e . "n";
}

3.2 Python

class AggregateError(Exception):
    def __init__(self, errors):
        super().__init__()
        self.errors = errors

    def __str__(self):
        return ', '.join(str(err) for err in self.errors)

def promise1():
    return Promise.resolve("Success 1")

def promise2():
    return Promise.reject("Error 2")

def promise3():
    return Promise.reject("Error 3")

def aggregate_errors(promises):
    errors = []
    for p in promises:
        try:
            result = await p
            print(result)
        except Exception as e:
            errors.append(e)
    if errors:
        raise AggregateError(errors)

promises = [promise1(), promise2(), promise3()]
try:
    await aggregate_errors(promises)
except AggregateError as e:
    print(e)

3.3 Shell

#!/bin/bash

function promise1 {
    echo "Success 1"
}

function promise2 {
    echo "Error 2" >&2
    exit 1
}

function promise3 {
    echo "Error 3" >&2
    exit 1
}

promises=(promise1 promise2 promise3)

for p in "${promises[@]}"; do
    if ! $p; then
        errors+=("$?")
    fi
done

if [ ${#errors[@]} -gt 0 ]; then
    echo "AggregateError: ${errors[*]}"
fi

3.4 SQL

CREATE TABLE errors (
    id INT PRIMARY KEY AUTO_INCREMENT,
    error_message VARCHAR(255)
);

DELIMITER $$

CREATE PROCEDURE aggregate_errors()
BEGIN
    DECLARE done INT DEFAULT FALSE;
    DECLARE error_message VARCHAR(255);
    DECLARE cur CURSOR FOR SELECT error_message FROM errors;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

    OPEN cur;

    read_loop: LOOP
        FETCH cur INTO error_message;
        IF done THEN
            LEAVE read_loop;
        END IF;
        INSERT INTO errors (error_message) VALUES (error_message);
    END LOOP;

    CLOSE cur;
END$$

DELIMITER ;

四、总结

本文深入探讨了如何实现一个具备聚合功能的 AggregateError,以处理多个并行 Promise 失败的场景。通过分析不同编程语言中的实现方式,我们可以更好地理解聚合错误处理的概念和实际应用。在实际项目中,合理地使用聚合错误处理,可以提高代码的健壮性和可维护性。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注