programing

복귀를 기다리는 약속과 복귀를 약속하는 약속의 차이

lovejava 2023. 7. 23. 13:55

복귀를 기다리는 약속과 복귀를 약속하는 약속의 차이

아래 코드 샘플을 고려할 때 동작에 차이가 있습니까? 만약 있다면, 어떤 차이가 있습니까?

return await promise

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

return promise

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

제가 알기로는 첫 번째는 비동기 함수 내에서 오류 처리를 하고, 비동기 함수의 Promise에서 오류가 거품처럼 튀어나올 것입니다.그러나 두 번째는 체크 표시가 하나 더 적게 필요합니다.이거 맞는건가요?

이 스니펫은 참조용으로 약속을 반환하는 일반적인 기능입니다.

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

대부분의 경우, 관측 가능한 차이는 없습니다.return그리고.return await의 두 버전 모두delay1Second정확히 동일한 관찰 가능한 동작을 가지고 있습니다(그러나 구현에 따라,return await의 경우 가 조금 더될 수 .Promise개체가 생성될 수 있음).

, @가 한 가지 : @PitaJ 지듯이했적가, @PitaJ 차다경하있습, 이가있우가: 니나에약만는만하지▁the▁however만▁if▁where:에약pit다▁@습▁there▁as니있▁out하나,rence:우는가▁there▁@▁diffe.return또는return await는 에내됨에 되어 있습니다.try-catch이. 이 예를 생각해 보십시오.

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!'
  }
}

첫 번째 버전에서 비동기 함수는 결과를 반환하기 전에 거부된 약속을 대기하므로 거부가 예외로 전환되고catch도달할 절. 따라서 함수는 "Saved!" 문자열로 확인하는 약속을 반환합니다.

그러나 두 번째 버전의 함수는 비동기 함수 내에서 거부된 약속을 기다리지 않고 직접 반환합니다. 즉,catch사례가 호출되지 않고 발신자가 대신 거부를 받습니다.

다른 답변에서 언급했듯이, 약속을 직접 반환함으로써 약속을 부풀릴 때 약간의 성과 이익이 있을 수 있습니다. 단순히 먼저 결과를 기다렸다가 다시 다른 약속으로 마무리할 필요가 없기 때문입니다.하지만 아직 아무도 테일최적화에 대해 이야기하지 않았습니다.

테일최적화 또는 "적절한 테일"은 인터프리터가 콜 스택을 최적화하기 위해 사용하는 기술입니다.기술적으로는 ES6 Standard의 일부이지만, 현재는 아직 많은 런타임이 지원하지 않지만, 향후 지원이 추가될 수도 있으므로 현재 좋은 코드를 작성하여 이에 대비할 수 있습니다.

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

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

때부터delay()의 직접반다니됩에서 직접 합니다.delay1Second() supporting PTC의 .delay1Second()(외부 함수), 그러나 다른 프레임을 여는 대신delay()(내부 기능), 외부 기능에 대해 열린 것과 동일한 프레임을 다시 사용합니다.이것은 스택을 최적화합니다. 왜냐하면 스택 오버플로(hehehe)를 방지할 수 있기 때문입니다.fibonacci(5e+25)본질적으로 그것은 훨씬 빠른 루프가 됩니다.

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

하지만 앞서 말했듯이 대부분의 런타임과 브라우저는 아직 PTC를 지원하지 않기 때문에 지금은 큰 차이가 없을 수도 있지만 미래에 코드를 보호하는 데는 큰 문제가 되지 않습니다.

이 질문에서 자세히 알아보기:Node.js: 비동기 함수에서 테일 콜에 대한 최적화가 있습니까?

눈에 띄는 차이: 약속 거부는 다른 위치에서 처리됩니다.

  • return somePromise 상담 사이트에 약속을 전달할 것입니다.await 사이트에서 해결하기로 약속합니다(있는 경우).따라서 일부 약속이 거부되면 로컬 캐치 블록이 아닌 콜 사이트의 캐치 블록에서 처리됩니다.

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거부되었습니다.

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()(출처).왜냐면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. await다음 시간까지 기다립니다.delayPromise해결되었습니다.
  • 한다면delayPromisePromiseValue=1:
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]]에서 변경된 pendingresolved또는rejected

대답하기 입니다. (아마도 어질문니다입려운대기하답이은것prob▁your다니▁this▁to질입▁(pil▁trans문ably)에 달려있기 때문입니다. 왜냐하면 실제로는 트랜스파일러가 어떻게 작동하는지에 달려있기 때문입니다(아마도).babel 렌더링합니다.async/await이와 관계없이 명확한 것은 다음과 같습니다.

  • 두 구현 모두 동일하게 동작해야 합니다. 첫 구현은 하나만 더 적을 수 있습니다.Promise

  • 특히 당신이 불필요한 것들을 떨어뜨린다면.await두 번째 버전은 트랜스파일러의 추가 코드를 요구하지 않지만 첫 번째 버전은 요구합니다.

따라서 코드 성능 및 디버깅 관점에서 볼 때, 두 번째 버전이 더 바람직하지만, 두 번째 버전은 약간의 가독성 이점이 있는 반면 첫 번째 버전은 약속을 반환한다는 것을 명확하게 나타냅니다.

저희 프로젝트에서는 항상 'return wait'을 사용하기로 했습니다.그 주장은 "나중에 트라이캐치 블록에 반환 표현 주위에 놓였을 때 '대기'를 추가하는 것을 잊어버릴 위험이 지금 중복된 '대기'를 갖는 것을 정당화한다"는 것입니다.

다음은 실행하여 "반환 대기"가 필요하다고 확신할 수 있는 유형의 스크립트 예제입니다.

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")
});

여기서 나는 당신이 이해할 수 있도록 실용적인 코드를 남깁니다.

 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의 함수를 호출하기 위해 대기를 호출하고, 완료되면 "sysc / wait"에 대해 정상적인 코드 순서를 따르지만, x 함수 내부에는 다른 비동기 함수가 있고, 이것은약속을 반환하거나 "x 함수 안에 머물며 주 코드를 잊어버리므로" console.log를 인쇄하지 않습니다."("more code .")라는 약속을 반환합니다.반면에, "), 만약 우리가 "를 넣는다면, 그것은 "그것은 메인 코드의 정상적인 순서를 따르고 완료되는 모든 함수를 기다릴 것입니다.

"delete the" return" (1 "delete the" return") 아래에 있는 동작을 볼 수 있습니다.

언급URL : https://stackoverflow.com/questions/38708550/difference-between-return-await-promise-and-return-promise