[javascript] 자바 스크립트는 호기심을 약속합니다

이 promise를 호출하면 출력이 함수 호출 순서와 일치하지 않습니다. 는 .then전과 제공 .catch과 약속은 비록 .then후에 호출되고 있었다. 그 이유는 무엇입니까?

const verifier = (a, b) =>
  new Promise((resolve, reject) => (a > b ? resolve(true) : reject(false)));

verifier(3, 4)
  .then((response) => console.log("response: ", response))
  .catch((error) => console.log("error: ", error));

verifier(5, 4)
  .then((response) => console.log("response: ", response))
  .catch((error) => console.log("error: ", error));

산출

node promises.js
response: true
error: false



답변

이것은 바닥에 도달하기위한 일종의 멋진 질문입니다.

이렇게하면 :

verifier(3,4).then(...)

새로 거부 된 promise .catch()가 다음 핸들러를 실행하기 전에 이벤트 루프로 다시 돌아 가야하는 새로운 promise를 반환 합니다. 추가주기는 다음 시퀀스를 제공합니다.

verifier(5,4).then(...)

첫 번째 핸들러가 큐에 들어가고 항목이 FIFO 순서로 큐에서 실행 되기 전에 이미 큐에 있었기 때문에 .then()이전 라인보다 먼저 핸들러 를 실행할 기회 ..catch().catch()


.then(f1, f2)대신에 양식 을 사용하면 .then().catch()추가 약속이 없으므로 추가 틱이 필요하지 않기 때문에 예상 할 때 실행됩니다.

const verifier = (a, b) =>
  new Promise((resolve, reject) => (a > b ? resolve(true) : reject(false)));

verifier(3, 4)
  .then((response) => console.log("response (3,4): ", response),
        (error) => console.log("error (3,4): ", error)
  );

verifier(5, 4)
  .then((response) => console.log("response (5,4): ", response))
  .catch((error) => console.log("error (5,4): ", error));

또한 모든 메시지에 레이블을 지정하여 어떤 verifier()호출에서 오는지 확인할 수 있으므로 출력을 훨씬 쉽게 읽을 수 있습니다.


약속 콜백 주문에 대한 ES6 사양 및 자세한 설명

ES6 사양은 약속 “작업”( .then()또는 에서 콜백을 호출 .catch()할 때)이 작업 대기열에 삽입되는시기를 기준으로 FIFO 순서로 실행 됨을 알려줍니다 . FIFO라는 이름은 구체적으로 지정하지 않지만 새 작업이 대기열 끝에 삽입되고 작업이 대기열의 처음부터 실행되도록 지정합니다. 이는 FIFO 주문을 구현합니다.

PerformPromiseThen (에서 콜백을 실행 함 .then())은 확인 또는 거부 처리기가 실제로 실행되도록 예약되는 방법 인 EnqueueJob이어 집니다. EnqueueJob은 보류중인 작업이 작업 대기열의 뒤쪽에 추가되도록 지정합니다. 그런 다음 NextJob 작업은 대기열의 앞쪽에서 항목을 가져옵니다. 이렇게하면 Promise 작업 대기열에서 작업을 처리 할 때 FIFO 순서가 보장됩니다.

따라서 원래 질문의 예에서 verifier(3,4)promise에 대한 콜백 과 verifier(5,4)Promise가 실행 된 순서대로 작업 대기열에 삽입 된 Promise는 두 원래 promise가 모두 수행 되었기 때문입니다. 그런 다음 인터프리터가 이벤트 루프로 돌아 가면 먼저 verifier(3,4)작업을 선택합니다 . 그 약속은 거부되었으며 verifier(3,4).then(...). 따라서 verifier(3,4).then(...)반환 된 promise를 거부 하고 verifier(3,4).then(...).catch(...)핸들러가 jobQueue에 삽입됩니다.

그런 다음 이벤트 루프로 돌아가고 jobQueue에서 가져 오는 다음 작업이 verifier(5, 4)작업입니다. 해결 된 약속과 해결 처리기가 있으므로 해당 처리기를 호출합니다. 이로 인해 response (5,4):출력이 표시됩니다.

그런 다음 이벤트 루프로 돌아가고 jobQueue에서 가져 오는 다음 작업은 해당 verifier(3,4).then(...).catch(...)작업을 실행하는 작업이며 이로 인해 error (3,4)출력이 표시됩니다.

때문이다 .catch()1 체인이보다는 그 체인에 한 약속 수준 깊은 .then()신고 순서를 일으키는 원인이되는 2 체인이다. 그리고 약속 체인이 동기식이 아닌 FIFO 순서로 작업 대기열을 통해 한 수준에서 다음 수준으로 이동하기 때문입니다.


이 수준의 일정 세부 정보 사용에 대한 일반 권장 사항

참고로, 일반적으로이 수준의 상세한 타이밍 지식에 의존하지 않는 코드를 작성하려고합니다. 호기심이 많고 때로는 이해하는 것이 유용하지만 코드에 대한 단순한 변경으로 인해 상대적인 타이밍이 변경 될 수 있으므로 깨지기 쉬운 코드입니다. 따라서 이와 같은 두 체인간에 타이밍이 중요하다면이 수준의 자세한 이해에 의존하는 것보다 원하는 방식으로 타이밍을 강제하는 방식으로 코드를 작성하는 것이 좋습니다.


답변

Promise.resolve()
  .then(() => console.log('a1'))
  .then(() => console.log('a2'))
  .then(() => console.log('a3'))
Promise.resolve()
  .then(() => console.log('b1'))
  .then(() => console.log('b2'))
  .then(() => console.log('b3'))

출력 a1, a2, a3, b1, b2, b3 대신 같은 이유로 인해 a1, b1, a2, b2, a3, b3이 표시됩니다. 매번 약속을 반환하고 이벤트 루프의 끝으로 이동합니다. 열. 그래서 우리는이 “약속 경주”를 볼 수 있습니다. 중첩 된 약속이있을 때도 마찬가지입니다.


답변