如何包装来自第三方api的错误?

时间:2019-04-04 16:22:14

标签: javascript

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

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

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

到目前为止还可以。

如果我确实发送了无效的数据,或者如果我打破了一些先决条件,则API会因大量数据和信息而引发一些重大错误。问题在于这些错误对用户不友好。

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

我已经创建了以下代码段:

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,但我不明白为什么它不起作用。

感谢您的帮助,谢谢。

3 个答案:

答案 0 :(得分:1)

使用决心,拒绝诺言。

此处(您的代码):

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));
}

答案 1 :(得分:1)

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

答案 2 :(得分:0)

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

将其更改为Object.getOwnPropertyNames(Object.getPrototypeOf(auth))之后,我可以专注于大家都帮助过我的诺言:)

我最后的工作片段以这种方式结束:

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));

谢谢大家的帮助:)

相关问题