简体   繁体   English

异步等待使用和错误处理问题

[英]Async await usage and error handling woes

Both try's print Promise { <pending> } and the second one has an Unhandled Promise Rejection Warning . 两个都尝试打印Promise { <pending> } ,第二个有Unhandled Promise Rejection Warning I've had success just using Promises with .then and .catch, but there's some stuff I'd like to code in more of a synchronous way using async/await. 我已经成功使用了.then和.catch的Promises,但有些东西我想使用async / await以更多的同步方式进行编码。 Should I be using Yield instead perhaps? 我可能会使用Yield吗?

try {
  var tokens = getNewTokens('refresh-token', 1)
  console.log(tokens)
} catch (error) {
  console.log(error.message)
}

try {
  tokens = getNewTokens('no-such-refresh-token', 1)
  console.log(tokens)
} catch (error) {
  console.log(error.message)
}

function getRefreshToken (refreshToken, userId) {
  return new Promise((resolve, reject) => {
    if (refreshToken === 'refresh-token' && userId === 1) {
      return resolve({
        refreshToken: 'refresh-token',
        accessToken: 'jwt'
      })
    } else {
      const error = Error('Refresh token not found')
      return reject(error)
    }
  })
}

async function getNewTokens (refreshToken, userId) {
  if (!refreshToken || !userId) {
    throw Error('Missing params')
  }
  try {
    var result = await getRefreshToken(refreshToken, userId)
  } catch (error) {
    throw Error(error.message)
  }
  if (!result) {
    throw Error('Something went bonk')
  }
  // Do stuff..
  // get user from DB
  // update refresh token with a new one
  // make new jwt
  return {
    user: {
      id: 1,
      name: 'Jerry',
      role: 'admin'
    },
    newRefreshToken: 'new-refresh-token',
    newAccessToken: 'new-jwt'
  }
}

Using async and await does not make your whole program asynchronous. 使用asyncawait不会使整个程序异步。 It makes particular functions asynchronous. 它使特定函数异步。 In the end, async is syntactical sugar that makes writing promise code easier. 最后, async是语法糖,使得编写承诺代码更容易。

An async function returns a Promise . async函数返回Promise The code that calls the asynchronous function must treat it as a function that returns a promise. 调用异步函数的代码必须将其视为返回promise的函数。 (The only exception is when the code that is calling the async function is itself in an async function, in which case it can be await ed.) (唯一的例外是当调用async函数的代码本身在async函数中时,在这种情况下可以await编辑。)

So throwing an Error gets translated into a Promise rejection. 因此抛出一个Error会被转化为Promise拒绝。 You can't catch it in a try..catch block for the simple reason that the try..catch is over way before the error is thrown! 您无法在try..catch块中捕获它,原因很简单, try..catch在抛出错误之前try..catch经过了! (Again, the exception is when you're calling it from an async function. If you are await ing an asynchronous function, a try..catch block will work. In this case the try..catch block is treated as if it were adding a Promise#catch function.) (同样,例外情况是当你从async函数调用它时。如果await异步函数, try..catch块将起作用。在这种情况下, try..catch块被视为是添加一个Promise#catch函数。)

You ultimately have to catch errors from an async function using the normal Promise#catch method or with the second argument to Promise#then : 您最终必须使用正常的Promise#catch方法或使用Promise#then的第二个参数从async函数中捕获错误:

getNewTokens('no-such-refresh-token', 1)
    .then(function(tokens) {
        console.log(tokens);
    }, function(error) {
        console.log(error.message);
    });

I would like to submit this as a reasonable and readable way to handle errors using async/await. 我想提交这个作为使用async / await处理错误的合理且可读的方法。

const value = await asyncFunction().catch(err => new Error(err))
if (value instanceof Error) return res.status(500).send('There was an error doing something')

By adding the .catch() method, which returns an Error , thus assigning it to the value variable , we can be sure that some value will be present in our variable. 通过添加返回 Error.catch()方法, 从而将其赋值给 value 变量 ,我们可以确定变量中会出现一些值。 The only additional line of code necessary is the if statement to test if the value is an instance of Error . 唯一需要的额外代码行是if语句来测试该值是否为Error的实例。 If it was caught for any reason, it will definitely be an instanceof Error (our code makes sure of that), and our program can safely handle that scenario (in the above case we are returning 500 as a server response, thus preventing the program from executing any dangerous code as a result of the error in the asyncFunction). 如果它因任何原因被捕获,它肯定会是一个错误的实例(我们的代码确保这一点),并且我们的程序可以安全地处理该场景(在上面的例子中,我们返回500作为服务器响应,从而阻止程序由于asyncFunction中的错误而执行任何危险代码)。

I intentionally wrote this in 2 lines to highlight the fact that this can be written tersely and avoid the use of try / catch blocks, which many do not enjoy reading (myself being one). 我故意用2行写这个,以突出这个事实,这可以简洁地写,避免使用try / catch块,许多人不喜欢阅读(我自己就是一个)。

If you're cool with reading try / catch blocks, congratulations. 如果你对阅读try / catch块很酷,恭喜你。 I just find it makes the code look janky. 我发现它使代码看起来很笨拙。 Oh well. 那好吧。 ¯\\_(ツ)_/¯

A practical answer for beginners in async/await and error handling async / await和错误处理中初学者的实用答案

You cannot use await syntax outside of a function that is not declared with async or is a promise. 您不能在未使用async声明的函数之外使用await语法,也不能使用promise。

async function myAsyncFunction() {
  // code
}

or 要么

const myPromiseFunction = () => new Promise((resolve, reject) => {
    // code
})

So ultimately, you have to use the old Promise way to consume a function declared as async 所以最终,你必须使用旧的Promise方法来使用声明为async的函数

myAsyncFunction().then(() => console.log('here'));

because both are Promises. 因为两者都是承诺。

Now to actually handle errors like you are used to in the then - catch way, you have to construct your async function like so... 我们真正处理的错误你是在当时的使用- 捕捞方式,你必须构建你的异步函数是这样的...

async function getUser(username) {
  return await db.users.get({ username });
}

then you can use this like a normal Promise outside of an async method like so... 然后你就可以像异步方法一样使用它像普通的Promise一样......

getUser()
.then(user => console.log(user))
.catch(err => console.error(err));

or you guessed it, use it within an async function using await. 或者你猜对了,使用await在异步函数中使用它。

async function getJoffery() {
  return await getUser('joffery');
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM