상세 컨텐츠

본문 제목

[자바스크립트] 동기 비동기적 이해

카테고리 없음

by esoesmio 2023. 5. 17. 20:42

본문

맨 뒤에것이 맨 앞에 나온다.

Promise.resolve('foo')
    // 1. "foo"를 받고 "bar"를 추가한 다음 그 값으로 이행하여 다음 then에 넘겨줌
    .then(function(string) {
        return new Promise(function(resolve, reject) {
            setTimeout(function() {
                string += 'bar';
                resolve(string);
            }, 1000);
        });
    })
    // 2. "foobar"를 받고 그대로 다음 then에 넘겨준 뒤,
    // 나중에 콜백 함수에서 가공하고 콘솔에 출력
    .then(function(string) {
        setTimeout(function() {
            string += 'baz';
            console.log(string);
        }, 1000)
        return string;
    })
    // 3. 이 부분의 코드는 이전의 then 블록 안의 (가짜) 비동기 코드에서
    // 실제로 문자열을 가공하기 전에 실행됨
    .then(function(string) {
        console.log("마지막 Then: 앗... 방금 then에서 프로미스 만들고 반환하는 걸 까먹어서 " +
            "출력 순서가 좀 이상할지도 몰라요");

        // 'baz' 부분은 setTimeout 함수로 비동기적으로 실행되기 때문에
        // 이곳의 string에는 아직 'baz' 부분이 없음
        console.log(string);
    });

// 로그 출력 결과 (순서대로):
// 마지막 Then: 앗... 방금 then에서 프로미스 만들고 반환하는 걸 까먹어서 출력 순서가 좀 이상할지도 몰라요
// foobar
// foobarbaz

3번째 then이 먼저나온다.

 

세번째는 그냥함수 첫번째는 동기 두번째는 비동기

 

 

이 코드의 동작을 이해하려면 JavaScript의 비동기 처리와 Promise의 동작 방식을 이해해야 합니다.

첫 번째 .then 블록에서는 new Promise를 반환하고 있습니다. 이 Promise는 setTimeout 함수 안에서 resolve가 호출되기 때문에, setTimeout에 지정된 시간(1초)이 지난 후에 이행됩니다.

두 번째 .then 블록에서는 비동기적으로 실행되는 setTimeout 함수 안에서 문자열을 가공하고 있지만, 그 결과를 반환하는 Promise를 만들지 않고 있습니다. 즉, 이 블록의 반환 값은 setTimeout 함수가 실행되기 전에 결정되고, 이행된 상태의 Promise로 다음 .then 블록으로 넘어갑니다.

그래서, 세 번째 .then 블록은 두 번째 .then 블록에서 반환한 Promise가 이미 이행된 상태이므로 즉시 실행되고, 그 결과가 먼저 출력됩니다. 그리고 setTimeout 함수가 실행되면서 두 번째 .then 블록에서 가공한 문자열이 나중에 출력되는 것입니다.

따라서 출력 순서는 다음과 같습니다:

세 번째 .then 블록: "마지막 Then: 앗... 방금 then에서 프로미스 만들고 반환하는 걸 까먹어서 출력 순서가 좀 이상할지도 몰라요"
세 번째 .then 블록: "foobar" (두 번째 .then 블록에서 반환한 문자열)
두 번째 .then 블록: "foobarbaz" (비동기적으로 가공한 문자열)
비동기 코드를 다룰 때는 이렇게 동작 순서가 복잡해질 수 있으므로, 코드의 동작을 정확히 예측하려면 Promise와 비동기 처리에 대한 깊은 이해가 필요합니다.





User
첫번째 then이랑 두번째 then이랑 뭐가달라?
ChatGPT
첫 번째 .then과 두 번째 .then은 Promise가 처리되는 방식에서 차이가 있습니다.

첫 번째 .then에서는 Promise를 반환하고 있습니다. 이 Promise는 setTimeout 함수 안에서 resolve가 호출되기 때문에, setTimeout에 지정된 시간(1초)이 지난 후에 이행됩니다. 따라서 이 Promise가 이행되기 전까지는 다음 .then 블록이 실행되지 않습니다.

하지만 두 번째 .then에서는 비동기적으로 실행되는 setTimeout 함수 안에서 문자열을 가공하고 있지만, 그 결과를 반환하는 Promise를 만들지 않고 있습니다. 이 함수는 비동기적으로 실행되지만, Promise를 반환하지 않기 때문에 이행 상태를 Promise 체인에 전달하지 않습니다. 즉, 이 블록의 반환 값은 setTimeout 함수가 실행되기 전에 결정되고, 이행된 상태의 Promise로 다음 .then 블록으로 넘어갑니다.

그래서 세 번째 .then 블록은 두 번째 .then 블록에서 반환한 Promise가 이미 이행된 상태이므로 즉시 실행되고, 그 결과가 먼저 출력됩니다.

이런 차이는 Promise와 비동기 처리의 동작 방식에 기반하며, 비동기 코드를 작성할 때는 이런 동작을 잘 이해하고 있어야 합니다.

 

 

 

이건 순서가 왜이러냐....

 

var p2 = new Promise(function(resolve, reject) {
    resolve(1);
});

p2.then(function(value) {
    console.log(value); // 1
    return value + 1;
}).then(function(value) {
    console.log(value + ' - 동기적으로 짜도 돌아감');
});
console.log("이게머지");

p2.then(function(value) {
    console.log('haha');
    console.log(value); // 1
    console.log('haha');
});

 

Promise의 동작 방식과 JavaScript의 이벤트 루프에 대해 이해하면 이 질문에 답변할 수 있습니다.

Promise의 .then 메소드는 항상 비동기적으로 동작합니다. 콜백 함수는 즉시 실행되지 않고, 대신 이벤트 루프의 마이크로태스크 큐에 추가됩니다. 마이크로태스크 큐의 콜백 함수는 현재 실행 중인 코드가 모두 완료된 후에 실행됩니다.

이 코드에서는 p2가 이미 이행된 상태의 Promise이므로, p2.then()을 호출하면 콜백 함수가 즉시 마이크로태스크 큐에 추가됩니다. 그러나 이 콜백 함수는 현재 실행 중인 코드가 모두 완료된 후에 실행되므로, "이게머지"가 먼저 출력됩니다.

그 다음에 이벤트 루프는 마이크로태스크 큐에서 가장 먼저 추가된 콜백 함수를 실행합니다. 이 코드에서 첫 번째 p2.then()의 첫 번째 콜백 함수와 두 번째 p2.then()의 콜백 함수가 거의 동시에 큐에 추가됩니다. JavaScript는 단일 스레드로 동작하므로, 두 콜백 함수가 동시에 실행되는 것은 불가능합니다. 따라서 두 콜백 함수의 실행 순서는 JavaScript 엔진의 내부 동작 방식에 따라 결정됩니다.

이 경우에는 두 번째 p2.then()의 콜백 함수가 먼저 실행되었음을 알 수 있습니다. 그 다음에 첫 번째 p2.then()의 두 번째 콜백 함수가 실행됩니다. 이 콜백 함수는 첫 번째 콜백 함수에서 반환된 값을 사용하므로, 첫 번째 콜백 함수가 완료된 후에만 실행될 수 있습니다.

따라서 출력 순서는 다음과 같습니다:

"이게머지"
"1"
"haha"
"1"
"haha"
"2 - 동기적으로 짜도 돌아감"
이렇게 Promise와 이벤트 루프의 동작 방식을 이해하면 비동기 코드의 동작 순서를 예측할 수 있습니다.
죄송합니다, 제 설명이 혼란을 준 것 같습니다. 올바른 순서로 다시 설명하겠습니다.

이 경우, .then 메소드는 다음과 같은 순서로 실행됩니다:

p2 프로미스가 resolve되면서 첫 번째 then 메소드의 첫 번째 콜백 함수가 마이크로태스크 큐에 추가됩니다. 이 콜백 함수는 console.log(value);와 return value + 1;를 실행합니다.

첫 번째 then 메소드의 두 번째 콜백 함수는 첫 번째 콜백 함수가 return한 값을 받아서 마이크로태스크 큐에 추가됩니다. 이 콜백 함수는 console.log(value + ' - 동기적으로 짜도 돌아감');을 실행합니다.

두 번째 then 메소드의 콜백 함수가 마이크로태스크 큐에 추가됩니다. 이 콜백 함수는 console.log('haha');, console.log(value);, console.log('haha');를 실행합니다.

이로 인해 출력 순서는 다음과 같습니다:

"1" - 첫 번째 then 메소드의 첫 번째 콜백 함수에서 출력됩니다.
"haha" - 두 번째 then 메소드의 콜백 함수에서 출력됩니다.
"1" - 두 번째 then 메소드의 콜백 함수에서 출력됩니다.
"haha" - 두 번째 then 메소드의 콜백 함수에서 출력됩니다.
"2 - 동기적으로 짜도 돌아감" - 첫 번째 then 메소드의 두 번째 콜백 함수에서 출력됩니다.
JavaScript는 단일 스레드로 동작하며, 이벤트 루프를 통해 비동기 동작을 처리합니다. 이벤트 루프는 마이크로태스크 큐에 있는 콜백 함수를 순서대로 처리합니다. 따라서 .then 메소드의 콜백 함수는 등록된 순서대로 실행됩니다. 하지만 이 경우에는 첫 번째 then 메소드의 두 번째 콜백 함수가 첫 번째 콜백 함수가 return한 값을 기다려야 하므로, 두 번째 then 메소드의 콜백 함수가 먼저 실행됩니다. 이로 인해 출력 순서가 위와 같이 나타납니다.

댓글 영역