‘return await promise’와 ‘return promise’의 차이점 그렇다면 그

아래 코드 샘플을 감안할 때 동작에 차이가 있습니까? 그렇다면 그 차이점은 무엇입니까?

return await promise

async function delay1Second() {
  return (await delay(1000));
}

return promise

async function delay1Second() {
  return delay(1000);
}

내가 이해했듯이 첫 번째는 비동기 함수 내에서 오류 처리가 가능하며 오류는 비동기 함수의 Promise에서 버블 링됩니다. 그러나 두 번째는 한 번 더 적은 틱이 필요합니다. 이 올바른지?

이 스 니펫은 참조를 위해 Promise를 반환하는 일반적인 함수입니다.

function delay(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}



답변

대부분의 경우 return와 사이에는 눈에 띄는 차이가 없습니다 return await. 두 버전 모두 delay1Second똑같은 관찰 가능한 동작 을 가지고 있습니다 (그러나 구현에 따라 return await중간 Promise객체가 생성 될 수 있으므로 버전이 약간 더 많은 메모리를 사용할 수 있음).

그러나 @PitaJ가 지적했듯이 차이가있는 경우가 있습니다. returnor return awaittrycatch블록에 중첩 된 경우 입니다. 이 예를 고려하십시오

async function rejectionWithReturnAwait () {
  try {
    return await Promise.reject(new Error())
  } catch (e) {
    return 'Saved!'
  }
}

async function rejectionWithReturn () {
  try {
    return Promise.reject(new Error())
  } catch (e) {
    return 'Saved!'
  }
}

첫 번째 버전에서 비동기 함수는 결과를 반환하기 전에 거부 된 promise를 기다립니다. 이로 인해 거부가 예외로 바뀌고 catch절에 도달하게됩니다. 따라서이 함수는 문자열 “Saved!”로 해결되는 promise를 반환합니다.

그러나 함수의 두 번째 버전은 async 함수 내에서 기다리지 않고 거부 된 promise를 직접 반환합니다. 즉, catch케이스가 호출 되지 않고 호출자가 대신 거부를받습니다.


답변

다른 답변에서 언급했듯이 약속을 직접 반환하여 버블 링 할 때 약간의 성능 이점이있을 수 있습니다. 그 이유는 결과를 먼저 기다린 다음 다른 약속으로 다시 래핑 할 필요가 없기 때문입니다. 그러나 아직 테일 콜 최적화에 대해 이야기 한 사람은 없습니다 .

테일 호출 최적화 또는 “적절한 테일 호출” 은 인터프리터가 호출 스택을 최적화하는 데 사용하는 기술입니다. 현재는 기술적으로 ES6 표준의 일부 임에도 불구 하고 아직 많은 런타임이 지원 하지는 않지만 향후 지원이 추가 될 수 있으므로 현재 좋은 코드를 작성하여 준비 할 수 있습니다.

간단히 말해서 TCO (또는 PTC) 는 다른 함수에서 직접 반환하는 함수에 대한 새 프레임을 열지 않음 으로써 호출 스택을 최적화합니다 . 대신 동일한 프레임을 재사용합니다.

async function delay1Second() {
  return delay(1000);
}

에서 delay()직접 반환 되므로 delay1Second()PTC를 지원하는 런타임은 먼저 delay1Second()(외부 함수)에 대한 프레임을 열지 만 (내부 함수)에 대해 다른 프레임을 여는 대신 delay()외부 함수에 대해 열린 동일한 프레임을 재사용합니다. 이것은 예를 들어, 매우 큰 재귀 함수 로 스택 오버플로 (hehe)를 방지 할 수 있기 때문에 스택을 최적화합니다 fibonacci(5e+25). 본질적으로 그것은 훨씬 더 빠른 루프가됩니다.

PTC는 내부 함수가 직접 반환되는 경우에만 활성화됩니다 . 함수의 결과가 반환되기 전에 변경 될 때 사용되지 않습니다 (예 : return (delay(1000) || null), 또는 return await delay(1000).

그러나 내가 말했듯이 대부분의 런타임과 브라우저는 아직 PTC를 지원하지 않으므로 지금은 큰 차이를 만들지 못하지만 코드의 미래 보장에는 해를 끼칠 수 없습니다.

이 질문에서 더 많은 것을 읽으십시오 : Node.js : 비동기 함수에서 꼬리 호출을위한 최적화가 있습니까?


답변

babel실제로 트랜스 파일러 (아마도 )가 실제로 렌더링 하는 방식에 따라 다르기 때문에 대답하기 어려운 질문 async/await입니다. 분명한 것 :

  • 첫 번째 구현 Promise 체인에서 하나가 적을 있지만 두 구현은 동일하게 작동해야합니다 .

  • 특히 불필요한을 삭제하면 await두 번째 버전은 트랜스 파일러의 추가 코드가 필요하지 않지만 첫 번째 버전은 필요합니다.

따라서 코드 성능 및 디버깅 관점에서 두 번째 버전이 더 바람직하지만 아주 약간만 그렇지만 첫 번째 버전은 약속을 반환한다는 것을 명확하게 표시한다는 점에서 약간의 가독성 이점이 있습니다.


답변

눈에 띄는 차이점 : 약속 거부는 다른 장소에서 처리됩니다.

  • return somePromisesomePromise 는 콜 사이트에 전달 하고 await somePromise 는 콜 사이트 (있는 경우)에 정산합니다. 따라서 somePromise가 거부되면 로컬 catch 블록이 처리하지 않고 호출 사이트의 catch 블록이 처리합니다.
async function foo () {
  try {
    return Promise.reject();
  } catch (e) {
    console.log('IN');
  }
}

(async function main () {
  try {
    let a = await foo();
  } catch (e) {
    console.log('OUT');
  }
})();
// 'OUT'

  • return await somePromise지역에 정착 하겠다는 약속 을 먼저 기다릴 것입니다 . 따라서 값 또는 예외가 먼저 로컬에서 처리됩니다. => somePromise거부 되면 로컬 catch 블록이 실행됩니다 .
async function foo () {
  try {
    return await Promise.reject();
  } catch (e) {
    console.log('IN');
  }
}

(async function main () {
  try {
    let a = await foo();
  } catch (e) {
    console.log('OUT');
  }
})();
// 'IN'

이유 : return await Promise로컬 및 외부 모두를 return Promise기다립니다.

세부 단계 :

약속 반환

async function delay1Second() {
  return delay(1000);
}
  1. 전화 delay1Second();
const result = await delay1Second();
  1. 내부 delay1Second()에서 함수 delay(1000)[[PromiseStatus]]: 'pending. 그것을라고 부르 자 delayPromise.
async function delay1Second() {
  return delayPromise;
// delayPromise.[[PromiseStatus]]: 'pending'
// delayPromise.[[PromiseValue]]: undefined
}
  1. 비동기 함수는 반환 값을 Promise.resolve()( Source ) 안에 래핑합니다 . delay1Second비동기 함수 이기 때문에 다음 이 있습니다.
const result = await Promise.resolve(delayPromise);
// delayPromise.[[PromiseStatus]]: 'pending'
// delayPromise.[[PromiseValue]]: undefined
  1. Promise.resolve(delayPromise)delayPromise입력이 이미 약속이기 때문에 아무것도하지 않고 반환합니다 ( MDN Promise.resolve 참조 ).
const result = await delayPromise;
// delayPromise.[[PromiseStatus]]: 'pending'
// delayPromise.[[PromiseValue]]: undefined
  1. awaitdelayPromise가 정착 될 때까지 기다립니다 .
  • delayPromisePromiseValue = 1로 충족되는 IF :
const result = 1; 
  • ELSE는 delayPromise거부됩니다.
// jump to catch block if there is any

반환 대기 약속

async function delay1Second() {
  return await delay(1000);
}
  1. 전화 delay1Second();
const result = await delay1Second();
  1. 내부 delay1Second()에서 함수 delay(1000)[[PromiseStatus]]: 'pending. 그것을라고 부르 자 delayPromise.
async function delay1Second() {
  return await delayPromise;
// delayPromise.[[PromiseStatus]]: 'pending'
// delayPromise.[[PromiseValue]]: undefined
}
  1. 현지 대기는 delayPromise정착 될 때까지 기다립니다 .
  • 사례 1 : delayPromisePromiseValue = 1로 충족됩니다.
async function delay1Second() {
  return 1;
}
const result = await Promise.resolve(1); // let's call it "newPromise"
const result = await newPromise;
// newPromise.[[PromiseStatus]]: 'resolved'
// newPromise.[[PromiseValue]]: 1
const result = 1; 
  • 사례 2 : delayPromise거부 됨 :
// jump to catch block inside `delay1Second` if there is any
// let's say a value -1 is returned in the end
const result = await Promise.resolve(-1); // call it newPromise
const result = await newPromise;
// newPromise.[[PromiseStatus]]: 'resolved'
// newPromise.[[PromiseValue]]: -1
const result = -1;

용어 사전:

  • 정착 : Promise.[[PromiseStatus]]변경 사항 pendingresolvedrejected


답변

여기에 실용적인 코드를 남겨 두었습니다.

 let x = async function () {
  return new Promise((res, rej) => {
    setTimeout(async function () {
      console.log("finished 1");
      return await new Promise((resolve, reject) => { // delete the return and you will see the difference
        setTimeout(function () {
          resolve("woo2");
          console.log("finished 2");
        }, 5000);
      });
      res("woo1");
    }, 3000);
  });
};

(async function () {
  var counter = 0;
  const a = setInterval(function () { // counter for every second, this is just to see the precision and understand the code
    if (counter == 7) {
      clearInterval(a);
    }

    console.log(counter);
    counter = counter + 1;
  }, 1000);
  console.time("time1");
  console.log("hello i starting first of all");
  await x();
  console.log("more code...");
  console.timeEnd("time1");
})();

“x”함수는 다른 함수보다 비동기 함수일뿐입니다. 반환 값을 삭제하면 “more code …”가 인쇄됩니다.

변수 x는 다른 비동기 함수를 갖는 비동기 함수일뿐입니다. 코드의 메인에서 변수 x의 함수를 호출하기 위해 대기를 호출합니다. 완료되면 코드 시퀀스를 따르며 이는 정상입니다. “async / await”에 대해, 그러나 x 함수 내부에는 또 다른 비동기 함수가 있습니다. 이것은 promise를 반환하거나 “promise를 반환합니다.”x 함수 안에 머물러 메인 코드를 잊어 버립니다. 즉, “console.log (“more code .. “), 반면에 우리가 넣으면”await “모든 기능이 완료 될 때까지 기다렸다가 마지막으로 메인 코드의 정상적인 순서를 따릅니다.

“console.log (“completed 1 “delete the”return “) 아래에 동작이 표시됩니다.


답변

다음은 “return await”가 필요하다는 것을 실행하고 확신 할 수있는 타이프 스크립트 예제입니다.

async function  test() {
    try {
        return await throwErr();  // this is correct
        // return  throwErr();  // this will prevent inner catch to ever to be reached
    }
    catch (err) {
        console.log("inner catch is reached")
        return
    }
}

const throwErr = async  () => {
    throw("Fake error")
}


void test().then(() => {
    console.log("done")
}).catch(e => {
    console.log("outer catch is reached")
});


답변