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

fre*_*yer 49 javascript try-catch promise async-await ecmascript-2017

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

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

console.log(createdUser)
// business
// logic
// goes
// here
Run Code Online (Sandbox Code Playgroud)

如果我错了,请纠正我,但似乎最好不要在机构中放置多行业务逻辑try,所以我只留下createdUser在块外声明,在块中分配它的替代方案,以及然后用它.

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

Ber*_*rgi 39

似乎最好不要在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
}
Run Code Online (Sandbox Code Playgroud)

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

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

    • catch块中的变量分配默认值
    • return早期或throwcatch块中取消例外
    • 设置一个标志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
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 测试捕获的异常的类型,并根据它处理或重新抛出它.

    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;
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    不幸的是,标准JavaScript(仍然)没有条件异常的语法支持.

  • 使用then两个回调而不是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
    });
    
    Run Code Online (Sandbox Code Playgroud)

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

  • @Saroj`const result = await something()。catch(err => fallback);`比`let result更简单; 尝试{结果=等待某事(); } catch(err){结果=后备;}`是的,在这种情况下,我认为这是个好主意。 (4认同)
  • 您的最后一个示例使用`.then()`来解决诺言并提供回调,因此,也许'await'在那里无效。 (2认同)
  • @dcorking 它是“await”由“.then(…)”调用返回的承诺。 (2认同)
  • 我见过有人直接把捕获处理程序附加到等待中。这样做或将其包装在try / catch中是一个好主意吗? (2认同)

Cal*_*twr 13

更干净的代码

将 async/await 与 Promise catch 处理程序一起使用。

据我所知,这是一个长期存在的问题,困扰着(两种意义上的)许多程序员及其代码。Promise.catch确实与 没有什么不同try/catch

ES6 Promise 的 catch 处理程序并与“await/async”和谐地工作,提供了正确的解决方案和更清晰的代码:

const createUser = await this.User
    .create(userInfo)
    .catch(error => console.error(error))

console.log(createdUser)
// business
// logic
// goes
// here
Run Code Online (Sandbox Code Playgroud)

请注意,虽然这回答了问题,但它消除了错误。在这种情况下,最好抛出异常,因为 (1) 此操作(创建用户)预计不会失败,并且 (2) 无论如何您都无法继续 - 该操作已出错:

const createUser = await this.User
    .create(userInfo)
    .catch(error => {
        // do what you need with the error
        console.error(error)

        // maybe send to Datadog or Sentry

        // don't gobble up the error
        throw error
    })

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

Run Code Online (Sandbox Code Playgroud)

学习catch好像不值得?

上面的清洁优势可能并不明显,但它会增加现实世界中复杂的异步操作。

举例来说,除了创建用户(this.User.create)之外,我们还可以推送通知(this.pushNotification)和发送电子邮件(this.sendEmail)。

this.User.create

this.User.create = async(userInfo) => {

    // collect some fb data and do some background check in parallel
    const facebookDetails = await retrieveFacebookAsync(userInfo.email)
        .catch(error => {
            // we can do some special error handling

            // and throw back the error
         })
    const backgroundCheck = await backgroundCheckAsync(userInfo.passportID)

    if (backgroundCheck.pass !== true) throw Error('Background check failed')

    // now we can insert everything
    const createdUser = await Database.insert({ ...userInfo, ...facebookDetails })

    return createdUser
}
Run Code Online (Sandbox Code Playgroud)

this.pushNotifcationthis.sendEmail

this.pushNotification = async(userInfo) => {
    const pushed = await PushNotificationProvider.send(userInfo)
    return pushed
})

this.sendEmail = async(userInfo) => {
    const sent = await mail({ to: userInfo.email, message: 'Welcome' })
    return sent
})
Run Code Online (Sandbox Code Playgroud)

编写操作:

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

// business logic here

return await Promise.all([
    this.pushNotification(userInfo),
    this.sendEmail(userInfo)
]).catch(error => {
    // handle errors caused
    // by pushNotification or sendEmail
})
Run Code Online (Sandbox Code Playgroud)

没有尝试/捕捉。并且很清楚您正在处理哪些错误。


nev*_*evf 7

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

const createdUser = await this.User.create(userInfo).catch( error => {
// handle error
})
Run Code Online (Sandbox Code Playgroud)