>  기사  >  웹 프론트엔드  >  JS의 Promise에 대한 심층적인 이해

JS의 Promise에 대한 심층적인 이해

yulia
yulia원래의
2018-09-10 14:52:321342검색

Promise를 사용할 때 가장 간단하게 이해하고 사용하는 방법은 위 코드와 같이 해결하기 위한 비동기 결과를 매개변수로 제공한 후, 결과 처리 함수로 사용자 정의 함수를 then 메소드에 전달하는 것입니다. 그런데 두 매개변수는 정확히 무엇입니까? 해결(Resolve) 및 거부(Reject) 그 이면에는 기본적인 작업 방식이 어떻게 되나요? 규범적인 관점에서 미리 살펴보겠습니다.

new Promise((resolve, reject) => setTimeout(resolve, 1000, 'foo'))  
 .then(console.log)  
 // foo (1s后)

TL;DR
1. Promise의 작동 메커니즘은 콜백의 작동 메커니즘과 유사하며 둘 다 내부 추상 작업 Job을 사용하여 비동기
2를 구현합니다. Promise 생성자의 해결/거부 함수는 내부적으로 생성됩니다. 전달된 매개변수는 파싱할 결과이며, Promise에 저장되어 있던 사용자가 전달한 처리 함수와 함께 Job Queue에 삽입됩니다. 전달된 매개변수는 Promise.all/race에서 내부적으로 사용되는 약속일 수도 있습니다.
3. Promise.prototype.then은 현재 Promise 상태에 따라 Promise에 저장된 결과를 즉시 꺼내어 매개변수의 처리 기능과 함께 Job 대기열에 직접 삽입할지, 아니면 먼저 Promise와 연결할지 결정합니다. 결과 처리 기능으로 약속드립니다. 그런 다음 Promise 생성 함수를 암시적으로 호출하여 새로운 Promise를 만들고 반환합니다.
4. Promise.all은 먼저 새 Promise를 생성한 다음, 해결된 Promise를 계산하기 위해 빈 결과 배열과 카운터를 초기화하고 각 반복 Promise 값에 대해 새로운 Promise를 생성합니다. 결과 배열에 결과와 카운터를 추가하겠다고 약속합니다. 최종 결과는 카운터가 0으로 감소할 때 확인됩니다.
5. Promise.race는 또한 새로운 기본 Promise를 생성합니다. Promise는 한 번만 해결될 수 있다는 제한 사항에 따라 각 반복 값에 대해 먼저 해결된 Promise가 반환됩니다. 주요 약속이 먼저 해결됩니다.

new Promise(executor)

우선 Promise 생성자부터 시작하겠습니다. 이는 전역 개체의 Promise 속성 값이므로 브라우저 환경에서 직접 호출할 수 있습니다. 문자열, 이러한 배열 생성자는 동일합니다.

new Promise(executor)의 첫 번째 단계는 다른 생성자와 동일합니다. Promise의 프로토타입에 따라 새 객체를 빌드하고 여러 내부 슬롯 [[PromiseState]], [[PromiseResult]], [[ PromiseFullfillReactions]], [ [PromiseRejectReactions]], [[PromiseIsHandled]]는 일부 관련 정보를 기록하는 데 사용됩니다. 해당 기능은 이름에서 대략적으로 유추할 수 있습니다. 여기서 [[PromiseResult]]를 제외한 초기값은 "pending", 빈 목록, 빈 목록, false입니다.

다음 단계에서 ES는 Promise 객체를 기반으로 Promise를 해결하는 데 사용되는 Resolve 함수와 Promise를 거부하는 데 사용되는 Reject 함수를 생성합니다. 그런 다음 Resolve 함수와 Reject 함수를 매개변수로 실행자를 호출합니다. 이 과정에서 오류가 발생하면 Promise를 직접 거부합니다. 마지막으로 반환 약속.

그럼 결심은 무엇이고 거절은 무엇인가요? 우리는 Promise의 상태, 즉 [[PromiseState]]가 보류 중, 완료됨, 거부됨의 세 가지 값을 갖는다는 것을 알고 있습니다. 거부 함수를 사용하여 약속을 거부하고 상태를 보류 중에서 거부됨으로 변경합니다. 그러나 해결 기능은 약속을 이행하여 약속의 상태를 보류 중에서 이행으로 변경하거나 약속을 거부하는 데 사용할 수 있습니다.

그렇다면 해결 기능과 거부 기능은 정확히 무엇을 하는 걸까요?

먼저 거부 함수를 살펴보겠습니다. 먼저 생성 시 [[Promise]] 및 [[AlreadyResolved]] 슬롯을 초기화합니다. 즉, Promise와 연결합니다. 실행 중에 이유 매개변수가 전달되며, [[AlreadyResolved]]가 false인 경우, 즉 해결되지 않고 상태가 보류 중인 경우에만 RejectPromise가 호출되고 promise 및 이유 매개변수가 반환됩니다. 그렇지 않으면 약속을 거부하기 위해 전달됩니다.
RejectPromise(promise, Reason), [[PromiseState]]를 보류에서 거부로 변경하는 것 외에도 Promise 결과 [[PromiseResult]]의 값을 Reason으로 설정하고 Promise의 [[PromiseRejectReactions]]를 제거합니다. (나중에 이 내부 슬롯에 레코드를 저장하는 작업이 있을 것이라는 점을 독자 여러분이 이해했다고 믿습니다.) TriggerPromiseReactions를 사용하여 후속 처리를 위해 이러한 레코드를 호출하고 거부 이유를 전달합니다. 마찬가지로, 해결 함수에 사용되는 FullfillPromise(promise, value) 작업은 promise 상태를 이행으로 변경하고, [[PromiseFullfillReactions]] 값을 추출하고, TriggerPromiseReactions를 호출하고, 이행된 결과 값을 전달합니다.

TriggerPromiseReactions(reactions, Argument)는 EnqueueJob("PromiseJobs", PromiseReactionJob, a3d76637d9f600fd49ff0ba4bc4aa381>)을 호출합니다. 이에 대해서는 나중에 자세히 설명하겠습니다.

Resolve 함수를 살펴보겠습니다. Reject 함수와 마찬가지로 생성되면 Promise와 연결됩니다. 실행하는 동안 우리가 전달하는 매개변수를 해상도라고 합니다. 약속이 해결되면 정의되지 않은 값이 반환됩니다. 그 이후의 상황은 비교적 복잡하다.

1. 사용자가 매개변수 확인으로 Promise 자체를 해결 함수에 전달하면 TypeError가 생성되고 발생하며 RejectPromise가 호출됩니다. 이유 매개변수는 이 TypeError입니다.
2. 해결 유형이 Object가 아닌 경우 FulfillPromise(promise, 해결)을 호출합니다.
3. 나머지 경우는 해결이 자신이 아닌 객체(Promise)인 경우입니다.
then이 없는 해상도가 객체인 경우 RejectPromise만 사용하세요.
then 속성이 있지만 호출할 수 없는 경우에도 FulfillPromise를 사용하세요.
then 속성이 있고 호출할 수 있는 경우 EnqueueJob("PromiseJobs", PromiseResolveThenableJob, 278cbe32429ed2462e7c7848320cdfcd>)만 사용하면 됩니다.
EnqueueJob을 설명하기에 앞서 먼저 Job이 무엇인지부터 살펴보겠습니다. 간단히 말하면 콜백의 내부 구현 메커니즘과 같습니다. "다른 ES가 실행되고 있지 않으면 해당 ES를 초기화하고 실행합니다." 실행될 FIFO 작업 큐와 실행 컨텍스트 및 실행 컨텍스트 스택을 실행하는 현재 실행 환경이 있습니다. 후자 두 개가 비어 있으면 첫 번째 작업 큐가 실행됩니다.

ES는 구현 시 ScriptJobs와 PromiseJobs라는 두 개 이상의 작업 대기열이 있어야 한다고 규정합니다. EnqueueJob("PromiseJobs", ...)을 호출하면 완료할 작업과 해당 매개변수가 PromiseJobs 대기열에 삽입됩니다. 보시다시피 Promise

1에는 두 가지 유형의 Job이 있습니다. PromiseReactionJob(reaction, 인수)
reaction에는 각각을 나타내는 3개의 내부 슬롯 [[Capability]], [[Type]] 및 [[Handler]]가 있습니다. [[연관 약속 및 관련 해결 기능과 거부 기능]], [[카테고리]], [[핸들러]]. 사용자가 핸들러(정의되지 않음)를 제공하지 않으면 카테고리가 Fulfill인지 Reject인지에 따라 인수가 결과로 사용됩니다. 핸들러가 제공되면 인수의 추가 처리에 사용됩니다. 마지막으로 Resolve 함수와 Reject 함수를 사용하여 이 결과를 기반으로 처리하고 반환합니다.
2. PromiseResolveThenableJob(promiseToResolve, thenable, then)
promiseToResolve와 관련된 확인 함수 및 거부 함수를 만듭니다. then을 호출 함수로 사용하고, 함수를 해결하고 함수를 거부하여 호출하고 반환할 매개변수로 사용하세요.

Promise.prototype.then(onfulfilled, onrejected)

첫 번째로 할 일은 새로운 약속과 관련 해결 기능 및 거부 기능이 포함된 promiseCapability를 만드는 것입니다. Promise 생성은 일반적으로 Promise 생성자를 사용하는 것과 동일하게 Promise를 작성하는 것이지만 생성자에 전달된 Executor는 내부적으로 자동으로 생성되며 그 기능은 PromiseCapability에 해결/거부 기능을 기록하는 것입니다. PromiseJobs에서 수행할 최종 작업인 promiseCapability 및 onfulfilled/onrejected를 기반으로 각각 이행 및 거부를 위한 두 개의 PromiseReactions를 생성합니다. 현재 Promise(this)가 보류 상태인 경우 이 두 반응을 Promise의 [[PromiseFulfillReactions]] 및 [[PromiseRejectReactions]] 대기열에 각각 삽입하세요. 그러나 이때 Promise가 이미 이행되거나 거부된 경우 Promise의 [[PromiseResult]]에서 값 결과가 꺼내어 이행 결과/거부 사유로 Job 대기열에 삽입됩니다. , a26f47e9cf9d76f551506ca748f96cb6>), 마지막으로 prjomiseCapability에 저장된 새로운 Promise를 반환합니다. Promise.prototype.catch(onrejected)는 Promise.prototype.then(undefine, onrejected)

Promise.resolve(x)

그때처럼 promiseCapability를 생성한 뒤, 거기에 있는 Resolve 함수를 직접 호출하고, 해결될 해상도 값 함수를 반복자 루프와 결합합니다. 1. 반복이 완료되고 카운터가 0이면 promiseCapability의 해결 함수를 호출하여 결과 배열을 해결합니다. 2. 그렇지 않으면 카운터가 다음과 같이 증가합니다. 1, 그런 다음 다음 반복의 값을 가져와 Promise.resolve에 전달하여 새 Promise도 빌드한 다음 내부적으로 Promise.all Resolve 요소 함수를 생성하고 이 새 Promise에 전달된 값을 사용하여 다음을 추가합니다. 결과를 결과 배열로 변환하고 카운터를 1씩 감소시킵니다.

Promise.race(iterable)마찬가지로 promiseCapability를 생성한 다음 반복하고 Promise.resolve를 사용하여 새 promise를 작성한 다음 이 새 promise의 then 메서드를 호출하고 promiseCapability의 해결/거부 함수를 전달합니다. 앞서 언급한 한 번만 해결되는 약속을 통해 우리는 이것이 실제로 매우 인종적이라는 것을 알 수 있습니다.

결론: 이걸 보고 다들 Promise에 대해 더 깊은 이해를 가지셨는지 궁금합니다. 한 단계 더 나아가 ES6에서 새로 제안된 async/await는 실제로 Generator와 Promise의 아이디어를 적용합니다. 관심이 있으시면 계속해서 자세히 알아볼 수 있습니다.

위 내용은 JS의 Promise에 대한 심층적인 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.