正确尝试...使用Async / Await捕获语法

时间:2017-06-20 22:15:16

标签: javascript promise async-await try-catch ecmascript-2017

我喜欢在Typescript等中提供的新Async/Await功能的平坦性。但是,我不确定我喜欢我必须声明变量我await的事实try...catch块的外部,以便稍后使用它。像这样:

let createdUser
try {
    createdUser = await this.User.create(userInfo)
} catch (error) {
    console.error(error)
}

console.log(createdUser)
// business
// logic
// goes
// here

如果我错了,请纠正我,但在try正文中放置多行业务逻辑似乎是的最佳做法,所以我只留下了在块外声明createdUser的替代方法,在块中指定它,然后在之后使用它。

在这种情况下,最佳做法是什么?

4 个答案:

答案 0 :(得分:28)

  

似乎最好不要在try主体中放置多行业务逻辑

其实我说的是。您通常希望使用以下值catch 所有例外:

try {
    const createdUser = await this.User.create(userInfo);

    console.log(createdUser)
    // business logic goes here
} catch (error) {
    console.error(error) // from creation or business logic
}

如果您只想从承诺中捕获和处理错误,您有三种选择:

  • 将变量声明为外部,并根据是否存在异常进行分支。这可以采取各种形式,如

    • catch
    • 中的变量指定默认值
    • return提前或重新throw来自catch区块的例外
    • 设置一个标记,catch块是否捕获了异常,并在if条件下对其进行测试
    • 测试已分配的变量的值

    let createdUser; // or use `var` inside the block
    try {
        createdUser = await this.User.create(userInfo);
    } catch (error) {
        console.error(error) // from creation
    }
    if (createdUser) { // user was successfully created
        console.log(createdUser)
        // business logic goes here
    }
    
  • 测试捕获的异常的类型,并根据它处理或重新抛出它。

    try {
        const createdUser = await this.User.create(userInfo);
        // user was successfully created
        console.log(createdUser)
        // business logic goes here
    } catch (error) {
        if (error instanceof CreationError) {
            console.error(error) // from creation
        } else {
            throw error;
        }
    }
    

    不幸的是,标准JavaScript(仍然)没有conditional exceptions的语法支持。

  • 使用then with two callbacks代替try / catch。这实际上是最不丑陋的方式,也是我个人的建议,因为它的简单性和正确性,不依赖于标记的错误或结果值的外观来区分履行的履行和拒绝:

    await this.User.create(userInfo).then(createdUser => {
        // user was successfully created
        console.log(createdUser)
        // business logic goes here
    }, error => {
        console.error(error) // from creation
    });
    

    当然它带有引入回调函数的缺点,这意味着你不能轻易地break / continue循环或从外部函数做早期return

答案 1 :(得分:4)

另一种更简单的方法是将.catch追加到promise函数。例如:

const createdUser = await this.User.create(userInfo).catch( error => {
// handle error
})

答案 2 :(得分:0)

@Bergi答案很好,但是我认为这不是最好的方法,因为您必须回到旧的then()方法,所以我认为更好的方法是捕获异步函数中的错误

async function someAsyncFunction(){
    const createdUser = await this.User.create(userInfo);

    console.log(createdUser)
}

someAsyncFunction().catch(console.log);
  • 但是如果我们在同一函数中有很多await并且需要捕获每个错误怎么办?

您可以声明to()函数

function to(promise) {
    return promise.then(data => {
        return [null, data];
    })
    .catch(err => [err]);
}

然后

async function someAsyncFunction(){
    let err, createdUser, anotherUser;

    [err, createdUser] = await to(this.User.create(userInfo));

    if (err) console.log(`Error is ${err}`);
    else console.log(`createdUser is ${createdUser}`);


    [err, anotherUser] = await to(this.User.create(anotherUserInfo));

    if (err) console.log(`Error is ${err}`);
    else console.log(`anotherUser is ${anotherUser}`);
}

someAsyncFunction();
  

在阅读此内容时:“等待this.User.create”。

最后,您可以创建模块“ to.js”或直接使用await-to-js模块。

您可以在this post中获得有关to函数的更多信息

答案 3 :(得分:0)

我通常在失败时使用Promise的catch()函数返回具有error属性的对象。

例如,在您的情况下,我会这样做:

const createdUser = await this.User.create(userInfo)
          .catch(error => { error }); // <--- the added catch

if (Object(createdUser).error) {
    console.error(error)
}

如果您不想继续添加catch()调用,则可以在该函数的原型中添加一个辅助函数:

Function.prototype.withCatcher = function withCatcher() {
    const result = this.apply(this, arguments);
    if (!Object(result).catch) {
        throw `${this.name}() must return a Promise when using withCatcher()`;
    }
    return result.catch(error => ({ error }));
};

现在您可以:

const createdUser = await this.User.create.withCatcher(userInfo);
if (Object(result).error) {
    console.error(result);
}