Javascript 使用Async/Await更正Try…Catch语法

Javascript 使用Async/Await更正Try…Catch语法,javascript,promise,async-await,try-catch,ecmascript-2017,Javascript,Promise,Async Await,Try Catch,Ecmascript 2017,我喜欢Typescript中新的Async/Await功能的平坦性,等等。但是,我不确定我是否喜欢这样一个事实:我必须在try…catch块的外部声明变量I'mAwaiting,以便以后使用它。像这样: let createdUser try { createdUser = await this.User.create(userInfo) } catch (error) { console.error(error) } console.log(createdUser) // b

我喜欢Typescript中新的
Async/Await
功能的平坦性,等等。但是,我不确定我是否喜欢这样一个事实:我必须在
try…catch
块的外部声明变量I'm
Await
ing,以便以后使用它。像这样:

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

console.log(createdUser)
// business
// logic
// goes
// here
如果我错了,请纠正我,但最好不要在
try
正文中放置多行业务逻辑,因此我只能选择在块外声明
createdUser
,在块中分配它,然后在之后使用它

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

在try主体中不放置多行业务逻辑似乎是最佳实践

事实上我想说是的。您通常希望捕获使用该值时出现的所有异常:

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
      early或re-
      catch
      块抛出异常
    • 设置标记
      catch
      块是否捕获异常,并在
      if
      条件下测试异常
    • 测试要分配的变量的值
  • 测试捕获的异常的类型,并基于该类型处理或重新引用它

      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(仍然)没有对的语法支持

    如果您的方法没有返回因特定错误而被拒绝的承诺,您可以通过在
    .catch()
    处理程序中重新抛出更合适的内容来实现这一点:

      try {
          const createdUser = await this.User.create(userInfo).catch(err => {
              throw new CreationError(err.message, {code: "USER_CREATE"});
          });
          …
      } …
    
    另请参阅此文件的预
    异步
    /
    等待
    版本

  • 使用而不是
    尝试
    /
    捕获
    。这确实是最不丑陋的方式,我个人的建议也是因为它的简单性和正确性,不依赖标记的错误或结果值的外观来区分承诺的履行和拒绝:

      await this.User.create(userInfo).then(createdUser => {
          // user was successfully created
          console.log(createdUser)
          // business logic goes here
      }, error => {
          console.error(error) // from creation
      });
    
    当然,它也有引入回调函数的缺点,这意味着您不能轻易地
    中断
    /
    继续
    循环,或者从外部函数提前执行
    返回
    s


另一种更简单的方法是在promise函数中附加.catch。例:

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

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

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

    console.log(createdUser)
}

someAsyncFunction().catch(console.log);
  • 但是,如果我们在同一个函数中有许多
    等待
    ,并且需要捕获每个错误,该怎么办
您可以声明
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”或简单地使用该模块


您可以在

中获得有关
to
函数的更多信息。我通常使用Promise的
catch()
函数在失败时返回带有
error
属性的对象

例如,在你的情况下,我会:

const createdUser=wait this.User.create(userInfo)
.catch(错误=>{error});//({error}));
};
现在您可以执行以下操作:

const createdUser=wait this.User.create.withCatcher(userInfo);
if(对象(createdUser).error){
console.error(createdUser.error);
}

2020年3月编辑

您还可以向
Promise
对象添加默认的“捕获错误对象”函数,如下所示:

Promise.prototype.catchToObj=函数catchToObj(){
返回这个.catch(error=>({error}));
};
然后按如下方式使用:

const createdUser=wait this.User.create(userInfo.catchToObj();
if(createdUser&&createdUser.error){
console.error(createdUser.error);
}

“最佳实践”是使用有效的、可理解的、可维护的等。。我们如何才能“正确”回答这个问题?我只需要使用
var
,知道变量将被提升。这是“错误”吗?try/catch应该准确地包含您想要捕获异常的内容。如果明确查找来自
this.User.create()
的错误,则不会在try/catch中放入任何其他内容。但是,在一个try块中放入一大堆逻辑也是一个非常合理的设计。这完全取决于您希望如何/在何处处理错误,以及您希望如何设计异常处理代码,以及对给定操作有何意义。没有通用的最佳实践。一个通用的最佳实践是确保以适当的方式捕获和处理所有错误。
async/await
是ES2017(今年的版本)的一部分,而不是ES6(两年前发布)。您的上一个示例使用
.then()
来解决承诺并提供回调,因此,
wait
可能没有任何效果。@dcorking它是
wait
在等待
返回的承诺。然后(…)
调用。
.then()
调用返回的lambda是否需要async关键字?我见过有人直接附加catch处理程序来等待。这样做是个好主意还是将其包装在try/catch中?@Saroj
const result=wait something().catch(err=>fallback)
let结果更简单;尝试{{结果=等待某事();} catch(Err){结果=后退;}:是的,在这种情况下,我认为这是个好主意。<代码>那么不比<代码>更糟,请等待< /C> >因为它更旧了。它只是不同,而且适合其他事情。另一方面,这种“
wait to(…)
样式”让人想起了具有所有缺点的nodeback样式。顺便说一句,为了获得更好的性能和简单性,您应该使用
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();