avatar
Published on

no return, await, return, await return 의 차이

Author
  • avatar
    Name
    yceffort

50% 확률로 reject 되는 아래와 같은 함수가 있다고 가정해보자.

async function resolveOrReject() {
  // 1초를 그냥 기다린다.
  await new Promise((_) => setTimeout(_, 1000))

  // 50% 확률로 true false
  const randomResult = Boolean(Math.round(Math.random()))

  if (randomResult) {
    return 'good'
  } else {
    throw Error('bad')
  }
}

그냥 호출

async function a() {
  try {
    resolveOrReject()
  } catch (e) {
    return 'caught!'
  }
}

이 경우 a()는 1초를 기다리지 않고 언제나 undefinedfulfilled (이행) 할 것이다. 우리가 여기에서 await 하거나 껼과를 기다리지 않으므로, 실패했을 경우에 대해서 처리를 할 수가 없다. 대부분 이런 코드는 실수일것이다.

await

async function b() {
  try {
    await resolveOrReject()
  } catch (e) {
    return 'caught!'
  }
}

이 함수의 경우에는 항상 1초를 기다리며, undefined가 오거나 caught가 올 것이다. resolveOrReject의 결과를 기다리기 때문에, 실패 했을 경우 catch 블록을 실행할 수 있게 되었다. 그러나 실패하지 않았을 경우에는 이 값을 가지고 아무것도 하지 않는다.

return

async function c() {
  try {
    return resolveOrReject()
  } catch (e) {
    return 'caught'
  }
}

이 경우에도 마찬가지로 1초를 기다리며, 성공할 경우 good 이 오고, 실패할 경우에는 caught가 오는 것이 아니고 그냥 에러가 던져진다. 따라서 실패할 경우엔 catch 블록에 들어가지 않는다는 것을 알 수 있다.

return await

async function d() {
  try {
    return await resolveOrReject()
  } catch (e) {
    return 'caught'
  }
}

1초를 기다리며, good이 오거나 caught가 오게 된다. resolveOrReject의 결과를 기다리므로, 에러가 났을 때는 catch 블록으로 , 이행이 되었을 경우 정상적으로 결과를 리턴한다.

위 함수를 나누면 이렇게 볼 수 있다.

async function d() {
  try {
    // resolveOrReject 의 결과를 기다리며, 결과를 변수에 넣는다.
    const result = await resolveOrReject()
    // 만약 위에서 에러가 던져졌다면, catch 블록으로 넘어간다.
    // 그렇지 않으면, 결과를 리턴한다.
    return result
  } catch (e) {
    return 'caught'
  }
}

이 것은 어디까지나 try ... catch 블록에서만 유효하다. 그 외의 영역에서는 return await은 의미하다. async 함수 내에 있는 return await은 프로미스를 기다렸다가 결과가 나올때까지, 현재의 함수를 콜스택에 넣어두며, 외부 promise가 resolve 되기전에 추가로 마이크로 태스크가 생기게 된다. 따라서 try ... catch 블록이 아니라면 단순히 return something으로 처리하면 된다.

https://github.com/eslint/eslint/blob/master/docs/rules/no-return-await.md