【问题标题】:How to wrap errors from third party api?如何包装来自第三方 api 的错误?
【发布时间】:2019-04-04 16:22:13
【问题描述】:

我确实使用第三方 API 来管理身份验证操作。

可用的方法返回promise,假设一个createUser方法,我可以这样调用:

this.auth.createUser(data).then(() => alert('user created'));

到目前为止还可以。

如果我确实发送了无效数据,或者如果我打破了一些先决条件,API 会抛出一些带有大量数据和信息的大错误。问题是这些错误对用户不友好。

我正在尝试包装这些方法,因此我可以抛出一个已知错误(特定标记)并向用户提供更好的消息,但到目前为止我无法做到。

我已经构建了这个 sn-p:

class Auth {
    createUser(...args) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                this.log(...args);
                throw new Error('auth service throws some error with a lot of details and info not user friendly');
            }, 3000);
        });
    }
    log(...args) { console.log('this', ...args) }
}

const auth = new Auth();

Object.keys(auth).forEach(key => {
    if (typeof auth[key] === 'function') {
        const originalFunction = auth[key];
        auth[key] = function() {
            try {
                return originalFunction.apply(this, arguments);
            } catch (e) {
                this.log('error', e);
                throw new Error('error-auth-' + nameFunctionAsTag(key));
            }
        };
    } else {
        console.log(typeof auth[key]);
    }
});

function nameFunctionAsTag(name) {
    return name.replace(/(?!^)[A-Z]/g, c => '-' + c.toLowerCase());
}

auth.log('auth service');

auth.createUser(1, 2, 3, 4, 5);

// expected: error-auth-create-user
// received: auth service throws some error with a lot of details and info not user friendly

正如在最后两行代码中所评论的那样,我预计会发现错误并收到error-auth-create-user,但我不明白为什么它不起作用。

任何帮助表示赞赏,在此先感谢。

【问题讨论】:

  • 在 setTimeout 中的 throw 与在 new Promise 中的 throw 是不同的上下文。改用拒绝
  • @charlietfl 我明白你的意思。但是假设 API 期望的某个字符串参数为 null,并且 API 尝试 null.toLowerCase(),它会像我的示例一样抛出,不是吗?我的意思是,如何在我的代码中捕获所有可能的错误/拒绝?
  • @charlietfl 现在我没明白你的意思……我已经用过 try catch。我无法更改 API 代码(它是第三方代码),上面的 createUser 只是我为模拟 API 错误而构建的一个示例。
  • 谢谢大家:)

标签: javascript


【解决方案1】:

在promise 中使用resolve 和reject。

这里(你的代码):

try {
    return originalFunction.apply(this, arguments); // asynchronous because of setTimeOut
} catch (e) {
    this.log('error', e);
    throw new Error('error-auth-' + nameFunctionAsTag(key));
}
// 3 second later, trigger exception out of try/catch statement

你可以做什么:

function asyncError(){
    return new Promise(function(resolve, reject){
        // ... code
        reject(new Error('Error ...'));
        // ... code
    })

}

async function test(){
    try{
        const experiment = await asyncError();
    }
    catch(e){
        console.log(e)
    }
}

其他方式(无需等待即可捕获):

function test2(){
    asyncError().catch((e) => console.log(e));
}

【讨论】:

  • 您的代码正在运行,但我无法更改第三方 API 代码,如果他们不拒绝,但抛出错误怎么办?另外,异步等待语法不会导致延迟吗?
  • 这就是Promise对象的目标,当reject或resolve触发时,异步返回promise
  • 刚刚编辑,每次通话后无需等待即可循环播放
【解决方案2】:

当您注册一个 Promise,甚至是一个 setTimeout 时,您并没有在同一个堆栈上下文中调用该函数。您实际上是在告诉引擎注册一个回调,系统稍后将使用正确的参数调用它。因此,错误永远不会冒泡到 try/catch。您可以在异步函数中使用 await 关键字来暂停执行并稍后返回,保持相同的上下文,这将保留此处使用的 try/catch 块。这是你需要在这里做的。签出:https://levelup.gitconnected.com/the-definite-guide-to-handling-errors-gracefully-in-javascript-58424d9c60e6

【讨论】:

  • 嗯..你是说我不能在setTimeout 中测试throw new Error(),因为它是一个新的范围(有道理)......那么,我该如何测试我的try catch ?我在这里使用异步等待是唯一的选择吗?
  • @WashingtonGuedes try/catch 块是专门为 JS 中的同步错误处理而构建的,不幸的是这很少有用。如果您的错误是异步的,您需要使用其中一种异步方法(错误优先回调、承诺拒绝等)。 async/await 是使用 try/catch 处理异步错误的唯一方法,因为它允许您暂停堆栈的执行。我鼓励你使用等待/异步。它并不难学,而且是对抗回调地狱中潜在未来的有用武器。
【解决方案3】:

刚刚发现主要问题:Object.keys(auth) 在类实例上返回空数组。

将其更改为 Object.getOwnPropertyNames(Object.getPrototypeOf(auth)) 后,我可以专注于你们帮助我完成的承诺 :)

我最后的工作 sn-p 以这种方式结束:

class Auth {
    createUser(...args) {
        return Promise.resolve().then(() => {
            this.log(...args);
            throw new Error('auth service throws some error with a lot of details and info not user friendly');
        });
    }
    log(...args) { console.log('this', ...args) }
}

const auth = new Auth();

Object.getOwnPropertyNames(Object.getPrototypeOf(auth)).forEach(key => {
    if (key === 'constructor') return;

    if (typeof auth[key] === 'function') {
        const originalFunction = auth[key];
        auth[key] = function() {
            return Promise.resolve()
                .then(() => originalFunction.apply(this, arguments))
                .catch(e => {
                    this.log('error', e.message);
                    throw new Error('error-auth-' + nameFunctionAsTag(key));
                });
        };
    }
});

function nameFunctionAsTag(name) {
    return name.replace(/(?!^)[A-Z]/g, c => '-' + c.toLowerCase());
}

auth.log('auth service');
auth.createUser(1, 2, 3, 4, 5).catch(e => console.log('final error:', e.message));

谢谢大家的帮助:)

【讨论】:

    猜你喜欢
    • 2018-12-14
    • 1970-01-01
    • 2020-11-14
    • 1970-01-01
    • 1970-01-01
    • 2016-10-28
    • 2022-01-07
    • 2022-06-15
    • 1970-01-01
    相关资源
    最近更新 更多