当前位置: 首页 > 面试题库 >

Javascript承诺模式-区分错误

夏奕
2023-03-14
问题内容

考虑以下代码块:

    getUser(userId)
    .catch(function(error){
        crashreporter.reportError('User DB failed', error);
        // show user a generic error
    })
    .then(function(user) {
        return chargeCreditCard(user);
    })
    .catch(function(error){
        crashreporter.reportError('Credit card failed', error);
        // show user an error saying that their credit card got rejected
    })

显然,与此有关的问题是,如果用户DB失败,则将执行THEN(USER)块。另一种选择是将第一个捕获块移动到链的末尾。但是,这会引起另一个问题!我们将无法区分错误是来自用户数据库还是信用卡。

我认为解决了以下问题的以下模式是否被视为无极反模式?有更好的方法吗?我看到的问题是,您可能会陷入半回调地狱。

    getUser(userId)
    .then(function(user) {
        return chargeCreditCard(user)
              .catch(function(error){
                  crashreporter.reportError('Credit card failed', error);
                  // show user an error saying that their credit card got rejected
              });
    })
    .catch(function(error){
        crashreporter.reportError('User DB failed', error);
        // show user a generic error
    })

编辑:我想我还不太清楚。如果还有更多的THEN块,该怎么办,如下所示。问题在于,一旦遇到一个错误,就根本不希望链继续。

getUser(userId)
    .then(function(user) {
        return chargeCreditCard(user);
    }, function(error){
        crashreporter.reportError('User DB failed', error);
        // show user a error 1
    })
    .then(function(chargeId) {
        return saveChargeId(chargeId);
    }, function(error){
        crashreporter.reportError('ChargeId DB failed', error);
        // show user a error 2
    })
    .then(function(chargeHistoryId) {
        return associateChargeToUsers(chargeHistoryId);
    }, function(error){
        crashreporter.reportError('chargeHistoryId DB failed', error);
        // show user a error 3
    })
    .catch(function(error){
        crashreporter.reportError('Credit card failed', error);
        // show user a error 4
    })

问题答案:

我认为解决了以下问题的以下模式是否被视为无极反模式?

不,还好。

有更好的方法吗?

是的,看看和之间.then(…).catch(…)``.then(…,…)。如果要严格区分成功案例(继续)和错误案例(报告此特定问题),则将两个回调传递给then是一个更好的主意。这样,外部处理程序将不会由于成功案例代码中的失败而被触发,而只能由安装它的Promise中的失败触发。在您的情况下:

getUser(userId)
.then(function(user) {
    return chargeCreditCard(user)
    .then(function(chargeId) {
        return saveChargeId(chargeId)
        .then(function(chargeHistoryId) {
            return associateChargeToUsers(chargeHistoryId);
            .then(function(result) {
                return finalFormatting(result);
            }, function(error){
                crashreporter.reportError('chargeHistoryId DB failed', error);
                return 3;
            });
        }, function(error){
            crashreporter.reportError('ChargeId DB failed', error);
            return 2;
        });
    }, function(error){
        crashreporter.reportError('Credit card failed', error);
        return 4;
    });
}, function(error){
    crashreporter.reportError('User DB failed', error);
    return 1;
})
.then(showToUser);

尽管您可能想使用通用错误处理程序:

getUser(userId)
.catch(function(error){
    crashreporter.reportError('User DB failed', error);
    throw new Error(1);
})
.then(function(user) {
    return chargeCreditCard(user)
    .catch(function(error){
        crashreporter.reportError('Credit card failed', error);
        throw new Error(4);
    });
})
.then(function(chargeId) {
    return saveChargeId(chargeId);
    .catch(function(error){
        crashreporter.reportError('ChargeId DB failed', error);
        throw new Error(2);
    });
})
.then(function(chargeHistoryId) {
    return associateChargeToUsers(chargeHistoryId);
    .catch(function(error){
        crashreporter.reportError('chargeHistoryId DB failed', error);
        throw new Error(3);
    });
})
.then(function(result) {
    return finalFormatting(result);
}, function(error) {
    return error.message;
})
.then(showToUser);

在这里,每个then回调都会返回一个承诺,该承诺会自行拒绝并产生相应的错误。理想情况下,每个被调用的函数都已经做到了,当它们没有这样做时,您需要catch向每个函数附加一个特定的参数,您可能想使用包装器辅助函数(可能是crashreporter?的一部分)。

function withCrashReporting(fn, msg, n) {
    return function(x) {
        return fn(x)
        .catch(function(error){
            crashreporter.reportError(msg, error);
            throw new Error(n);
        });
    };
}
withCrashReporting(getUser, 'User DB failed', 1)(userId)
.then(withCrashReporting(chargeCreditCard, 'Credit card failed', 4))
.then(withCrashReporting(saveChargeId, 'ChargeId DB failed', 2))
.then(withCrashReporting(associateChargeToUsers, 'chargeHistoryId DB failed', 3))
.then(finalFormatting, function(error) {
    return error.message;
})
.then(showToUser);

我看到的问题是,您可能会陷入半回调地狱。

不,这只是包装的适当水平。与回调地狱相反,它可以展平为最大嵌套数为2,并且始终具有返回值。

如果您绝对想避免嵌套和回调,请使用async/ await,尽管实际上更加难看:

try {
    var user = await getUser(userId);
} catch(error) {
    crashreporter.reportError('User DB failed', error);
    return showToUser(1);
}
try {
    var chargeId = chargeCreditCard(user);
} catch(error) {
    crashreporter.reportError('Credit card failed', error);
    return showToUser(4);
}
try {
    var chargeHistoryId = saveChargeId(chargeId);
} catch(error) {
    crashreporter.reportError('ChargeId DB failed', error);
    return showToUser(2);
}
try {
    var result = associateChargeToUsers(chargeHistoryId);
} catch(error) {
    crashreporter.reportError('chargeHistoryId DB failed', error);
    return showToUser(3);
}
return showToUser(finalFormatting(result));


 类似资料:
  • 问题内容: 编辑 继续重试直到承诺解决的模式(带有delay和maxRetries)。 在结果满足条件之前一直重试的模式(带有delay和maxRetries)。 具有无限重试次数(提供延迟)的高效内存动态模式。 #1的代码。 继续重试,直到承诺解决为止(该语言是否有任何改进社区?) 采用 #2的代码会 继续重试,直到条件以可重用的方式满足条件为止(条件会有所不同)。 问题答案: 有点不同… 异步

  • 问题内容: 我正在尝试用正确的方法表示正确的方法,以指示内发生故障。 如果诺言没有失败,(即返回诺言的操作是否正常工作,例如返回状态200的AJAX请求),但是我认为结果无效,通常我会这样做弹出窗口,向用户说明问题,然后执行“返回假”;尽早退出该方法。 但是,有了承诺,如果我想从.then()内部做类似的事情,我就被引导去相信我应该做的是抛出一个错误,而应该让它被.catch()抓住。 ),我已经

  • 问题内容: 问题1:在给定的时间只允许一个API请求,因此,真正的网络请求在尚未完成的情况下排队。应用可以随时调用API级别,并且期望得到回报。当API调用排入队列时,将在将来的某个时刻创建对网络请求的承诺- 返回什么给应用程序?这样可以通过延迟的“代理”承诺来解决: 问题2:对一些API调用进行反跳动,以便随着时间的推移累积要发送的数据,然后在达到超时时分批发送。调用API的应用期望得到回报。

  • 问题内容: 我已经在多个地方阅读了诺言处理程序模式,但我不知道它是什么。建议我在如下代码中使用它: 什么是Proposal Disposer模式,在这里如何应用? 注意-在本机的Promise中,我做为“添加返回值但执行操作的拒绝和实现处理程序”。在这种情况下,我会使用蓝鸟。 问题答案: 您的代码有问题 上述方法的问题在于,如果您在每次执行操作后都忘记释放连接,则可能会导致资源泄漏,当应用程序耗尽

  • 问题内容: 我对诺言不太熟悉。我想从承诺电话中隐藏承诺的实现。 例: 然后我将在同一文件中而不是在同一函数中解决我的诺言,我称其为诺言。 现在,我知道“ promiseFriend”是不确定的。我如何才能将承诺电话与承诺解决方案区分开? 问题答案: 如果要在函数中定义一个promise并在其他地方使用它,则首先需要从该函数返回promise,而您在代码中没有这样做。然后,您需要实际调用您也没有执行

  • 问题内容: 因此,我希望我的第一级捕获是处理错误的捕获。反正有没有将我的错误传播到第一个陷阱? 参考代码,尚不可用: 问题答案: 使用新的异步/等待语法,您可以实现此目的。请注意,在编写本文时,并非所有浏览器都支持此功能,您可能需要使用babel(或类似的东西)来转换代码。