Javascript ES6 Promises가 해결 후에도 계속 실행되는 이유는 무엇입니까?


97

약속은 resolve () 또는 reject () 할 수 있다는 것을 이해하지만 약속의 코드가 resolve 또는 reject가 호출 된 후에도 계속 실행된다는 사실을 알고 놀랐습니다.

나는 모든 즉각적인 함수 실행을 중단시키는 exit 또는 return의 비동기 친화적 버전 인 resolve 또는 reject를 고려했습니다.

누군가가 다음 예제에서 해결 호출 후 console.log를 표시하는 이유에 대한 생각을 설명 할 수 있습니까?

var call = function() {
    return new Promise(function(resolve, reject) {
        resolve();
        console.log("Doing more stuff, should not be visible after a resolve!");
    });
};

call().then(function() {
    console.log("resolved");
});

jsbin


12
합리적인 질문이지만 다시 JS는 당신이 말한 것처럼 문장을 하나씩 실행합니다. resolve()마술처럼 효과가있는 JS 제어문이 return아니라 함수 호출 일 뿐이며 실행이 계속됩니다.

이것은 좋은 질문이다, 심지어 모든 응답을 읽은 후, 나는 ... 모범 사례에 대해 잘 모르겠어요
가브리엘 글렌

오해는 resolve ()로 정확히 종료하는 것에서 비롯된 것이라고 생각합니다. promise는 resolve ()를 호출 한 직후에 해결되지만 다른 사람들이 이미 말했듯이 약속을 종료 한 함수가 종료되었다는 의미는 아닙니다. 의무도 있으므로 "정상"종료에 도달 할 때까지 계속됩니다.
Giuseppe Bertone

답변:


143

JavaScript에는 "완료까지 실행" 이라는 개념이 있습니다. 오류가 발생하지 않으면 return명령문 또는 그 끝에 도달 할 때까지 함수가 실행 됩니다. 함수 외부의 다른 코드는이를 방해 할 수 없습니다 (다시 오류가 발생하지 않는 한).

당신이 원하는 경우에 resolve()당신의 initialiser 기능을 종료하려면하여 앞에 추가해야합니다 return:

return new Promise(function(resolve, reject) {
    return resolve();
    console.log("Not doing more stuff after a return statement");
});

Hi Felix-이것은 이야기의 일부일 뿐이라고 생각합니다. 다른 부분은 그 resolve()자체가 비동기 함수라는 것입니다. 다른 (삭제 된) 답변에서 보았 듯이 일부 사람들은 전화 resolve가 즉시 콜백을 실행 한다고 믿습니다 .
Alnitak 2015 년

3
@Alnitak resolve자체는 비동기식이 아니며 완전히 동기식입니다. 엄격하게 ES6 API를 사용하더라도 동기식이든 비동기식이든 관찰 할 수 없습니다.
Esailija 2015 년

1
@Esailija 좋아, 아마도 나는 불분명했다. 어떤 사람들은 호출 resolve하면 등록 된 콜백이 즉시 호출되어 현재 호출 스택의 일부가된다고 생각합니다. 즉, 대신 그냥 콜백을 큐, 사실이 아니다 (그리고 맞아요, 그것은 비동기 아니지만 그냥 그 일을 즉시 종료)
알니 타크

@Alnitak : 나는 당신이 말하는 것을 이해합니다. 나는 단지 console.log왜 그것이 그 순서로 나타나는지 대신에 왜 나타나는지 로 해석했습니다 . 지금까지 resolve약속이 무엇을 하고 어떻게하는지는 내가 질문을 해석하는 방법과 관련이 없습니다. 그러나 물론 약속의 맥락에서 아는 것이 여전히 중요합니다. 이유 중 하나는 나는 당신의 대답 : upvoted
펠릭스 클링을

9
@Bergi, 편집에서 "return resolve ();"라고 말합니다. 특이한 것 같습니다. 중요한 것이 없다는 것을 확신하기 위해 문서를 읽고 (1) resolve ()가 결과를 반환하지 않는 것 같고 (2) 초기화 콜백의 반환 값이 그렇지 않다는 것을 확인해야했습니다. 사용되는 것으로 보입니다. "resolve (); return;"이라고 말하는 것이 더 명확하지 않을까요? 이 산만 함을 피할 수 있습니까?
Don Hatch

19

resolve약속을 할 때 호출되는 콜백 은 여전히 ​​사양에서 비동기 적으로 호출되어야합니다. 이는 동기 및 비동기 작업의 혼합에 대한 promise를 사용할 때 일관된 동작을 보장하기위한 것입니다.

따라서 resolve콜백 을 호출 하면 대기열 에 추가되고 resolve()호출 이후의 모든 코드와 함께 함수 실행이 즉시 계속 됩니다.

JS 이벤트 루프가 다시 제어권을받은 후에 만 ​​콜백이 대기열에서 제거되고 실제로 호출 될 수 있습니다.


1
콜백 대기열은 A + Specs 또는 ES6?
thefourtheye

5
@thefourtheye : 이벤트 루프 사양은 실제로 HTML5의 일부입니다 . ES6는에 EnqueueJob의해 호출되는 라는 내부 메서드를 정의합니다 .then.
Felix Kling 2015 년

@thefourtheye : 실제로 ES6도 대기열을 정의하는 것 같습니다 : people.mozilla.org/~jorendorff/… . 이벤트 루프와 관련된 것이 어느 쪽이든 상관 없습니다.
Felix Kling

나는이 그것이 어떻게 작동하는지 것을 알았지 만, 장과 절을 인용 없습니다 - 링크에 대한 감사를 @FelixKling
알니 타크

2
@FelixKling은 마이크로 태스크 / 매크로 태스크입니다. "실행중인 실행 컨텍스트가없고 실행 컨텍스트 스택이 비어있을 때 ECMAScript 구현은 작업 큐에서 첫 번째 PendingJob을 제거하고 포함 된 정보를 사용"하는 "Defers"사양의 일부입니다. 실행 컨텍스트를 생성하고 연관된 Job 추상 작업의 실행을 시작합니다. "
Benjamin Gruenbaum 2015 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.