찾다
웹 프론트엔드JS 튜토리얼진정으로 이해해야 할 약속

진정으로 이해해야 할 약속

관련 학습 권장 사항: javascript 학습 튜토리얼

약속 API에 관해서는 누구나 능숙하게 사용할 수 있어야 하지만, 여전히 마이크로 태스크와 관련된 지식 사각지대가 있을 수 있습니다.

전제 지식

본문을 시작하기 전에 이 기사에 포함된 일부 내용의 분위기를 미리 설정해 보겠습니다.

Promise 마이크로태스크와 관련된 API는 무엇인가요?

Promise에서는 then, catchfinally와 같이 상태 변경이 관련된 후에 실행해야 하는 콜백만 마이크로 작업으로 간주됩니다. 다른 모든 코드 실행은 매크로 작업(동기 실행)입니다. thencatchfinally ,其他所有的代码执行都是宏任务(同步执行)。

진정으로 이해해야 할 약속

上图中蓝色为同步执行,黄色为异步执行(丢到微任务队列中)。

这些微任务何时被加入微任务队列?

这个问题我们根据 ecma 规范来看:

  • 如果此时 Promise 状态为 pending,那么成功或失败的回调会分别被加入至 [[PromiseFulfillReactions]][[PromiseRejectReactions]] 中。如果你看过手写 Promise 的代码的话,应该能发现有两个数组存储这些回调函数。

  • 如果此时 Promise 状态为非 pending 时,回调会成为 Promise Jobs,也就是微任务。

了解完以上知识后,正片开始。

同一个 then,不同的微任务执行

初级

Promise.resolve()
  .then(() => {    console.log("then1");    Promise.resolve().then(() => {      console.log("then1-1");
    });
  })
  .then(() => {    console.log("then2");
  });复制代码

以上代码大家应该都能得出正确的答案:then1 → then1-1 → then2

虽然 then 是同步执行,并且状态也已经变更。但这并不代表每次遇到 then 时我们都需要把它的回调丢入微任务队列中,而是等待 then 的回调执行完毕后再根据情况执行对应操作。

基于此,我们可以得出第一个结论:链式调用中,只有前一个 then 的回调执行完毕后,跟着的 then 中的回调才会被加入至微任务队列。

中级

大家都知道了 Promise resolve 后,跟着的 then 中的回调会马上进入微任务队列。

那么以下代码你认为的输出会是什么?

let p = Promise.resolve();

p.then(() => {  console.log("then1");  Promise.resolve().then(() => {    console.log("then1-1");
  });
}).then(() => {  console.log("then1-2");
});

p.then(() => {  console.log("then2");
}); 
复制代码

按照一开始的认知我们不难得出 then2 会在 then1-1 后输出,但是实际情况却是相反的。

基于此我们得出第二个结论:每个链式调用的开端会首先依次进入微任务队列。

接下来我们换个写法:

let p = Promise.resolve().then(() => {  console.log("then1");  Promise.resolve().then(() => {    console.log("then1-1");
  });
}).then(() => {  console.log("then2");
});

p.then(() => {  console.log("then3");
});复制代码

上述代码其实有个陷阱,then 每次都会返回一个新的 Promise,此时的 p 已经不是 Promise.resolve() 生成的,而是最后一个 then 生成的,因此 then3 应该是在 then2 后打印出来的。

顺便我们也可以把之前得出的结论优化为:同一个 Promise 的每个链式调用的开端会首先依次进入微任务队列。

高级

以下大家可以猜猜 then1-2 会在何时打印出来?

Promise.resolve()
  .then(() => {    console.log("then1");    Promise.resolve()
      .then(() => {        console.log("then1-1");        return 1;
      })
      .then(() => {        console.log("then1-2");
      });
  })
  .then(() => {    console.log("then2");
  })
  .then(() => {    console.log("then3");
  })
  .then(() => {    console.log("then4");
  });复制代码

这题肯定是简单的,记住第一个结论就能得出答案,以下是解析:

  • 第一次 resolve 后第一个 then 的回调进入微任务队列并执行,打印 then1

  • 第二次 resolve 后内部第一个 then 的回调进入微任务队列,此时外部第一个 then 的回调全部执行完毕,需要将外部的第二个 then 回调也插入微任务队列。

  • 执行微任务,打印 then1-1then2,然后分别再将之后 then 中的回调插入微任务队列

  • 执行微任务,打印 then1-2then3 ,之后的内容就不一一说明了

接下来我们把 return 1 修改一下,结果可就大不相同啦:

Promise.resolve()
  .then(() => {    console.log("then1");    Promise.resolve()
      .then(() => {        console.log("then1-1");        return Promise.resolve();
      })
      .then(() => {        console.log("then1-2");
      });
  })
  .then(() => {    console.log("then2");
  })
  .then(() => {    console.log("then3");
  })
  .then(() => {    console.log("then4");
  });复制代码

当我们 return Promise.resolve() 时,你猜猜 then1-2 会何时打印了?

答案是最后一个才被打印出来。

为什么在 then 中分别 return진정으로 이해해야 할 약속

위 그림에서 파란색은 동기 실행을 나타내고 노란색은 비동기 실행(마이크로태스크 대기열에 던져짐)을 나타냅니다. 🎜

이러한 마이크로태스크는 언제 마이크로태스크 대기열에 추가되나요? 🎜🎜ecma 사양에 따라 이 문제를 살펴보겠습니다. 🎜
  • 🎜현재 Promise 상태가 보류 중이면 성공 또는 실패한 콜백이 [[PromiseFulfillReactions]] 및 <code>[[PromiseRejectReactions]]. 손으로 작성한 Promise 코드를 살펴보면 이러한 콜백 함수를 저장하는 배열이 두 개 있다는 것을 알 수 있습니다. 🎜
  • 🎜현재 Promise 상태가 보류 중이 아닌 경우 콜백은 마이크로태스크인 Promise Job이 됩니다. 🎜
🎜위의 지식을 이해한 후 본편이 시작됩니다. 🎜

같으면 다른 마이크로 작업 실행🎜

초급🎜
if (x instanceof MyPromise) {  if (x.currentState === PENDING) {
  } else {
    x.then(resolve, reject);
  }  return;
}复制代码
🎜누구나 할 수 있어야 합니다. 위 코드 정답을 제시하세요: then1 → then1-1 → then2. 🎜🎜then이 동기적으로 실행되어 상태가 변경되었지만. 하지만 이것이 then을 만날 때마다 콜백을 마이크로태스크 대기열에 던져야 한다는 의미는 아닙니다. 대신 then의 콜백이 완료될 때까지 기다려야 합니다. 그런 다음 상황에 따라 해당 작업을 수행하십시오. 🎜🎜이를 바탕으로 첫 번째 결론을 내릴 수 있습니다. 체인 호출에서는 이전 then 콜백이 실행된 후에만 다음 만 수행됩니다. Strong>then의 콜백이 마이크로태스크 대기열에 추가됩니다. 🎜

중급 🎜🎜모두가 Promise 해결 후에 다음 then의 콜백이 즉시 Enter라는 것을 알고 있습니다. 마이크로태스크 큐. 🎜🎜그러면 다음 코드의 출력은 어떻게 될까요? 🎜rrreee🎜초기 이해에 따르면 then2then1-1 다음에 출력될 것이라고 결론을 내리는 것은 어렵지 않지만 실제 상황은 그 반대입니다. 🎜🎜이를 바탕으로 우리는 두 번째 결론을 내립니다.각 체인 호출의 시작은 먼저 마이크로태스크 대기열에 순차적으로 들어갑니다. 🎜🎜다음으로 작성 방식을 바꿔 보겠습니다. 🎜rrreee🎜위 코드에는 실제로 트랩이 있습니다. then은 이때마다 p를 반환합니다. 더 이상 Promise.resolve()에 의해 생성되지 않고 마지막 then에 의해 생성되므로 then3은 then2 code>가 출력됩니다. 🎜🎜그런데 이전에 도달한 결론을 최적화할 수도 있습니다.동일한 Promise의 각 체인 호출이 시작되면 먼저 마이크로태스크 대기열에 순차적으로 들어갑니다. 🎜

Advanced🎜🎜 then1-2가 언제 인쇄될지 추측할 수 있나요? 🎜rrreee🎜이 질문은 확실히 간단합니다. 첫 번째 결론만 기억하면 답을 얻을 수 있습니다. 🎜
  • 🎜첫 번째 resolve 코드 콜백>then이 마이크로태스크 대기열에 들어가서 실행되어 then1🎜
  • 🎜두 번째 resolve 이후 첫 번째 내부 대기열을 인쇄합니다. then의 콜백은 마이크로태스크 큐에 들어갑니다. 이때 첫 번째 외부 then의 콜백이 모두 실행되었고, 두 번째 외부 then이 실행되었습니다. > 실행이 필요합니다. 콜백도 마이크로태스크 대기열에 삽입됩니다. 🎜
  • 🎜마이크로 작업을 실행하고 then1-1then2를 인쇄한 다음 각각 then에서 콜백을 호출합니다. the microtask queue🎜
  • 🎜microtask를 실행하고 then1-2then3를 인쇄하세요. 다음 내용은 하나씩 설명하지 않습니다🎜 li>
🎜다음으로 return 1을 수정했는데 결과는 상당히 다릅니다. 🎜rrreee🎜 return Promise.resolve() 를 사용하면 >then1-2가 인쇄됩니까? 🎜🎜정답은 마지막에 인쇄된 답변입니다. 🎜🎜 thenreturn이 다른데 왜 마이크로태스크의 실행 순서가 이렇게 크게 바뀌나요? 다음은 저자의 분석이다. 🎜

PS:then 返回一个新的 Promise,并且会用这个 Promise 去 resolve 返回值,这个概念需要大家先了解一下。

根据 Promise A+ 规范

根据规范 2.3.2,如果 resolve 了一个 Promise,需要为其加上一个 thenresolve

if (x instanceof MyPromise) {  if (x.currentState === PENDING) {
  } else {
    x.then(resolve, reject);
  }  return;
}复制代码

上述代码节选自手写 Promise 实现。

那么根据 A+ 规范来说,如果我们在 then 中返回了 Promise.resolve 的话会多入队一次微任务,但是这个结论还是与实际不符的,因此我们还需要寻找其他权威的文档。

根据 ECMA - 262 规范

根据规范 25.6.1.3.2,当 Promise resolve 了一个 Promise 时,会产生一个NewPromiseResolveThenableJob,这是属于 Promise Jobs 中的一种,也就是微任务。

This Job uses the supplied thenable and its then method to resolve the given promise. This process must take place as a Job to ensure that the evaluation of the then method occurs after evaluation of any surrounding code has completed.

并且该 Jobs 还会调用一次 then 函数来 resolve Promise,这也就又生成了一次微任务。

这就是为什么会触发两次微任务的来源。

最后

文章到这里就完结了,大家有什么疑问都可以在评论区提出。

想了解更多编程学习,敬请关注php培训栏目!

위 내용은 진정으로 이해해야 할 약속의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명
이 기사는 learnku에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제
C 및 JavaScript : 연결이 설명되었습니다C 및 JavaScript : 연결이 설명되었습니다Apr 23, 2025 am 12:07 AM

C 및 JavaScript는 WebAssembly를 통한 상호 운용성을 달성합니다. 1) C 코드는 WebAssembly 모듈로 컴파일되어 컴퓨팅 전력을 향상시키기 위해 JavaScript 환경에 도입됩니다. 2) 게임 개발에서 C는 물리 엔진 및 그래픽 렌더링을 처리하며 JavaScript는 게임 로직 및 사용자 인터페이스를 담당합니다.

웹 사이트에서 앱으로 : 다양한 JavaScript 애플리케이션웹 사이트에서 앱으로 : 다양한 JavaScript 애플리케이션Apr 22, 2025 am 12:02 AM

JavaScript는 웹 사이트, 모바일 응용 프로그램, 데스크탑 응용 프로그램 및 서버 측 프로그래밍에서 널리 사용됩니다. 1) 웹 사이트 개발에서 JavaScript는 HTML 및 CSS와 함께 DOM을 운영하여 동적 효과를 달성하고 jQuery 및 React와 같은 프레임 워크를 지원합니다. 2) 반응 및 이온 성을 통해 JavaScript는 크로스 플랫폼 모바일 애플리케이션을 개발하는 데 사용됩니다. 3) 전자 프레임 워크를 사용하면 JavaScript가 데스크탑 애플리케이션을 구축 할 수 있습니다. 4) node.js는 JavaScript가 서버 측에서 실행되도록하고 동시 요청이 높은 높은 요청을 지원합니다.

Python vs. JavaScript : 사용 사례 및 응용 프로그램 비교Python vs. JavaScript : 사용 사례 및 응용 프로그램 비교Apr 21, 2025 am 12:01 AM

Python은 데이터 과학 및 자동화에 더 적합한 반면 JavaScript는 프론트 엔드 및 풀 스택 개발에 더 적합합니다. 1. Python은 데이터 처리 및 모델링을 위해 Numpy 및 Pandas와 같은 라이브러리를 사용하여 데이터 과학 및 기계 학습에서 잘 수행됩니다. 2. 파이썬은 간결하고 자동화 및 스크립팅이 효율적입니다. 3. JavaScript는 프론트 엔드 개발에 없어서는 안될 것이며 동적 웹 페이지 및 단일 페이지 응용 프로그램을 구축하는 데 사용됩니다. 4. JavaScript는 Node.js를 통해 백엔드 개발에 역할을하며 전체 스택 개발을 지원합니다.

JavaScript 통역사 및 컴파일러에서 C/C의 역할JavaScript 통역사 및 컴파일러에서 C/C의 역할Apr 20, 2025 am 12:01 AM

C와 C는 주로 통역사와 JIT 컴파일러를 구현하는 데 사용되는 JavaScript 엔진에서 중요한 역할을합니다. 1) C는 JavaScript 소스 코드를 구문 분석하고 추상 구문 트리를 생성하는 데 사용됩니다. 2) C는 바이트 코드 생성 및 실행을 담당합니다. 3) C는 JIT 컴파일러를 구현하고 런타임에 핫스팟 코드를 최적화하고 컴파일하며 JavaScript의 실행 효율을 크게 향상시킵니다.

자바 스크립트 행동 : 실제 예제 및 프로젝트자바 스크립트 행동 : 실제 예제 및 프로젝트Apr 19, 2025 am 12:13 AM

실제 세계에서 JavaScript의 응용 프로그램에는 프론트 엔드 및 백엔드 개발이 포함됩니다. 1) DOM 운영 및 이벤트 처리와 관련된 TODO 목록 응용 프로그램을 구축하여 프론트 엔드 애플리케이션을 표시합니다. 2) Node.js를 통해 RESTFULAPI를 구축하고 Express를 통해 백엔드 응용 프로그램을 시연하십시오.

JavaScript 및 웹 : 핵심 기능 및 사용 사례JavaScript 및 웹 : 핵심 기능 및 사용 사례Apr 18, 2025 am 12:19 AM

웹 개발에서 JavaScript의 주요 용도에는 클라이언트 상호 작용, 양식 검증 및 비동기 통신이 포함됩니다. 1) DOM 운영을 통한 동적 컨텐츠 업데이트 및 사용자 상호 작용; 2) 사용자가 사용자 경험을 향상시키기 위해 데이터를 제출하기 전에 클라이언트 확인이 수행됩니다. 3) 서버와의 진실한 통신은 Ajax 기술을 통해 달성됩니다.

JavaScript 엔진 이해 : 구현 세부 사항JavaScript 엔진 이해 : 구현 세부 사항Apr 17, 2025 am 12:05 AM

보다 효율적인 코드를 작성하고 성능 병목 현상 및 최적화 전략을 이해하는 데 도움이되기 때문에 JavaScript 엔진이 내부적으로 작동하는 방식을 이해하는 것은 개발자에게 중요합니다. 1) 엔진의 워크 플로에는 구문 분석, 컴파일 및 실행; 2) 실행 프로세스 중에 엔진은 인라인 캐시 및 숨겨진 클래스와 같은 동적 최적화를 수행합니다. 3) 모범 사례에는 글로벌 변수를 피하고 루프 최적화, Const 및 Lets 사용 및 과도한 폐쇄 사용을 피하는 것이 포함됩니다.

Python vs. JavaScript : 학습 곡선 및 사용 편의성Python vs. JavaScript : 학습 곡선 및 사용 편의성Apr 16, 2025 am 12:12 AM

Python은 부드러운 학습 곡선과 간결한 구문으로 초보자에게 더 적합합니다. JavaScript는 가파른 학습 곡선과 유연한 구문으로 프론트 엔드 개발에 적합합니다. 1. Python Syntax는 직관적이며 데이터 과학 및 백엔드 개발에 적합합니다. 2. JavaScript는 유연하며 프론트 엔드 및 서버 측 프로그래밍에서 널리 사용됩니다.

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

에디트플러스 중국어 크랙 버전

에디트플러스 중국어 크랙 버전

작은 크기, 구문 강조, 코드 프롬프트 기능을 지원하지 않음

ZendStudio 13.5.1 맥

ZendStudio 13.5.1 맥

강력한 PHP 통합 개발 환경

DVWA

DVWA

DVWA(Damn Vulnerable Web App)는 매우 취약한 PHP/MySQL 웹 애플리케이션입니다. 주요 목표는 보안 전문가가 법적 환경에서 자신의 기술과 도구를 테스트하고, 웹 개발자가 웹 응용 프로그램 보안 프로세스를 더 잘 이해할 수 있도록 돕고, 교사/학생이 교실 환경 웹 응용 프로그램에서 가르치고 배울 수 있도록 돕는 것입니다. 보안. DVWA의 목표는 다양한 난이도의 간단하고 간단한 인터페이스를 통해 가장 일반적인 웹 취약점 중 일부를 연습하는 것입니다. 이 소프트웨어는

맨티스BT

맨티스BT

Mantis는 제품 결함 추적을 돕기 위해 설계된 배포하기 쉬운 웹 기반 결함 추적 도구입니다. PHP, MySQL 및 웹 서버가 필요합니다. 데모 및 호스팅 서비스를 확인해 보세요.

mPDF

mPDF

mPDF는 UTF-8로 인코딩된 HTML에서 PDF 파일을 생성할 수 있는 PHP 라이브러리입니다. 원저자인 Ian Back은 자신의 웹 사이트에서 "즉시" PDF 파일을 출력하고 다양한 언어를 처리하기 위해 mPDF를 작성했습니다. HTML2FPDF와 같은 원본 스크립트보다 유니코드 글꼴을 사용할 때 속도가 느리고 더 큰 파일을 생성하지만 CSS 스타일 등을 지원하고 많은 개선 사항이 있습니다. RTL(아랍어, 히브리어), CJK(중국어, 일본어, 한국어)를 포함한 거의 모든 언어를 지원합니다. 중첩된 블록 수준 요소(예: P, DIV)를 지원합니다.