如何从异步函数

时间:2017-03-21 11:54:01

标签: javascript node.js async-await

我有一个异步函数,我希望在失败时抛出异常。但似乎有些事情阻止了这一点:

通过省略try catch块,我希望抛出一个异常,我想在函数之外处理它。

我得到的实际结果有些令人困惑:

(node:10636) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): E11000 duplicate key error index.

(node:10636) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

async f(obj) {
    await db.collection('...').save(obj);
}

当我尝试捕获异常并抛出其他内容时,我得到相同的结果:

async f(obj) {
    try {
        await db.collection('...').save(obj);
    } catch(e) {
        throw e.message;
    }
}

该函数是从try块调用的,所以不要看这是一个未处理的Promise。

我正在尝试使用f作为另一个函数的参数:

g(obj, handler) {
    try {
        handler(obj);
    } catch(e);
        ...
    }
}

g(objToSave, f);

3 个答案:

答案 0 :(得分:16)

async f(obj) {
    try {
        await db.collection('...').save(obj);
    } catch(e) {
        throw e.message;
    }
}
  

该函数是从try块调用的,所以不要看这是一个未处理的Promise。

这里未处理的是拒绝f()函数返回的承诺,而不是.save()方法。所以这不会导致这个问题:

async f(obj) {
    try {
        await db.collection('...').save(obj);
    } catch(e) {
        console.error(e.message);
    }
}

在异步函数中抛出异常总是拒绝该函数返回的承诺

要捕获异常,您必须在另一个异步函数中执行此操作:

try {
    asyncFunc();
} catch (err) {
    // you have the error here
}

或者您可以明确添加拒绝处理程序:

asyncFunc().catch(err => {
    // you have the error here
});

如果你正在捕获异常并抛出另一个异常,那么你会遇到同样的问题,只是在一个不同的函数中。

您必须添加一个promise拒绝处理程序,而不是抛出异常或在那里返回被拒绝的promise - 或者在处理异常的另一个异步函数中运行该函数,而不是重新抛出相同或新的异常。

总结一下:每个async函数都会返回一个promise。每个承诺都需要有拒绝处理程序。

使用双功能.then().catch()try { await asyncFunction(); } catch (err) { ... }

添加拒绝处理程序

当您拒绝拒绝处理程序拒绝承诺时,您将在旧版本的Node中收到警告,并在较新版本的Node中收到致命错误 - 请参阅此答案以获取更多详细信息:

答案 1 :(得分:10)

最终,您尝试做的是在同步函数f中调用异步函数g,这不会起作用(这相当于能够将异步函数转换为同步函数。)

相反,g也必须是async,或者它应该正确处理f返回的承诺。但是,in this comment您声明由f表示的函数可能并不总是返回一个promise,在这种情况下,前一个选项最容易实现:

async g(obj, handler) {
  return await handler(obj);
}

如果handler没有返回承诺,而且只是一个值(记录为here),这也会有用。

再次调用g需要异步函数或代码来处理其返回的promise:

g(objToSave, f).then(...).catch(...)

答案 2 :(得分:1)

  

我想在函数之外处理

这是你唯一忘记做的事情。 (这就是为什么警告抱怨未处理的拒绝)。您的函数f工作正常。

您不能从async function抛出同步异常,一切都是异步的,异常会导致拒绝结果承诺。这就是你需要抓住的东西:

function g(obj, handler) {
    try {
        Promise.resolve(handler(obj)).catch(e => {
            console.error("asynchronous rejection", e);
        });
    } catch(e) {
        console.error("synchronous exception", e);
    }
}
// or just
async function g(obj, handler) {
    try {
        await handler(obj);
//      ^^^^^
    } catch(e) {
        console.error("error", e);
    }
}

g(objToSave, f);