상세 컨텐츠

본문 제목

[JavaScript] 출력되는 순서

카테고리 없음

by esoesmio 2024. 5. 14. 19:52

본문

async function a(){
    console.log('2');
    const a = await 1;
    console.log('4');
    console.log('a',a);
    console.log('hmm');
    await null;
    const b = await Promise.resolve(1);
    console.log('b', b);
    return a + b;
}
console.log('1');
const z = a().then().then();
console.log('3');
console.log('z',z);

 

 

JavaScript에서 비동기 코드와 동기 코드의 실행 순서를 이해하는 것이 중요합니다. 특히 `async/await`와 일반적인 동기 코드가 어떻게 상호작용하는지 살펴보겠습니다. 여기서 코드의 순서와 출력 결과를 이해하기 위해, JavaScript의 이벤트 루프와 실행 컨텍스트, 그리고 비동기 실행의 개념을 고려해야 합니다.

### 코드 실행 순서 분석:

1. **`console.log('1');`**
   - 이 코드는 동기적으로 실행되며, 프로그램 시작 시 가장 먼저 실행됩니다.
   - 출력: `1`

2. **`const z = a().then().then();`**
   - 여기서 `a()` 함수는 `async` 함수이므로 즉시 호출됩니다. `async` 함수는 호출될 때 함수 내부의 코드를 즉시 실행하지만, `await` 키워드를 만나는 순간 함수의 실행을 일시 중지하고, 프로미스의 해결을 기다립니다.
   - `a()` 함수 내부에서 첫 번째 출력은 `console.log('2');` 입니다. 이는 `await` 이전에 동기적으로 실행되므로 바로 출력됩니다.
   - 출력: `2`
   - `await 1`은 `Promise.resolve(1)`과 동등하게 처리되어, JavaScript 엔진은 이 프로미스가 해결될 때까지 다음 코드로 넘어가지 않습니다. 그러나 프로미스가 이미 해결된 상태이기 때문에, 다음 이벤트 루프 사이클에서 계속 실행됩니다.
   - 이후의 `.then()` 체인은 `a()` 함수가 완전히 해결된 후에 평가됩니다.

3. **`console.log('3');`**
   - 이 명령은 `a()` 함수 호출 이후 동기적으로 실행되며, `await`에 의해 함수 실행이 중단된 상황에서 바로 실행됩니다.
   - 출력: `3`

4. **`console.log('z', z);`**
   - 이 명령은 `z` 변수를 출력합니다. `z`는 `a()` 함수가 반환하는 프로미스에 두 개의 `.then()` 메소드가 체인으로 연결된 결과입니다. `a()` 함수의 완료를 기다리는 중이므로, 이 시점에서는 프로미스가 아직 해결되지 않은 'pending' 상태입니다.
   - 출력: `z Promise { <pending> }`

5. **`async` 함수 `a()` 내부의 나머지 코드 실행**
   - `await 1` 다음의 코드는 비동기적으로 처리되는 `await null` 이후에 실행됩니다.
   - 출력: `4`, `a 1`, `hmm`, `b 1`

### 결론:
이렇게 `1` 다음에 `2`, `3`, `z Promise { <pending> }`가 출력되는 이유는 `async` 함수 내에서 `await`을 만나면 그 지점에서 함수 실행이 일시 중지되고, 호출 스택이 비워져 다음 동기 코드가 실행되기 때문입니다. 그 후, 이벤트 루프는 다음 이터레이션에서 `await` 뒤의 코드를 계속 실행합니다. 이러한 실행 방식은 JavaScript의 비동기 처리의 핵심적인 부분으로, 이벤트 루프와 프로미스를 통해 동시성을 관리합니다.

 

async function a() {
    console.log('2');
    const a = await 1;
    console.log('4');
    console.log('a', a);
    console.log('hmm');
    await null;
    const b = await Promise.resolve(1);
    console.log('b', b);
    return a + b;
}

console.log('1');
const z = a().then(() => {
    console.log('in z');
    console.log('haha');
}).then(
    () => {
        console.log('and then');
    }
);
console.log('3');
console.log('z', z);

 

 

 

이 코드에서의 출력 순서를 이해하기 위해 `async/await`와 프로미스를 사용한 비동기 작업의 처리, 그리고 JavaScript의 이벤트 루프와 동기 및 비동기 작업의 실행 방식을 다시 살펴보겠습니다. 

1. **`console.log("kkkkkkkkkkkkkkk");`** - 이 부분은 주어진 코드에 없습니다만, 제일 처음에 실행될 것입니다.

2. **`console.log('1');`** - 이 로그는 메인 스크립트의 일부로, 동기적으로 실행되며 호출 스택에서 즉시 처리됩니다.
   - 출력: `1`

3. **`const z = a().then(...);`** - 여기서 `a()` 함수는 `async` 함수로, 즉시 호출됩니다. `async` 함수는 내부적으로 프로미스를 반환하며, 함수 내의 첫 `await` 표현식을 만날 때까지 동기적으로 실행됩니다.
   - `console.log('2');`는 `a()` 함수 내에서 `await` 이전에 호출되므로 즉시 실행됩니다.
   - 출력: `2`
   
4. **`console.log('3');`** - 이 로그는 `a()` 호출 후 바로 실행됩니다. 이 시점에서 `a()` 함수의 첫 번째 `await`에 의해 함수 실행이 비동기적으로 중단되었으므로, 메인 스크립트는 계속해서 실행됩니다.
   - 출력: `3`

5. **`console.log('z', z);`** - 이 시점에서 `z` 변수는 `a()` 함수의 반환값인 프로미스를 참조하고 있으며, 이 프로미스는 아직 해결되지 않았기 때문에 상태는 'pending'입니다.
   - 출력: `z Promise { <pending> }`

6. **`await 1` 이후의 코드 (`a()` 함수 내부)** - 첫 번째 `await` 이후의 코드는 이벤트 루프가 다시 해당 프로미스를 처리할 때까지 대기합니다. `Promise.resolve(1)`는 즉시 해결되므로, 다음 이벤트 루프 사이클에서 계속 실행됩니다.
   - `console.log('4');`
   - `console.log('a', a);`
   - `console.log('hmm');`
   - `await null;` 다음의 `console.log('b', b);`
   - 이러한 모든 로그가 연속적으로 출력됩니다.

7. **`.then()` 체인 처리** - `a()` 함수의 프로미스가 완료된 후, `.then()` 체인이 처리됩니다.
   - 첫 번째 `.then()`에서 `console.log('in z');`와 `console.log('haha');`가 실행됩니다.
   - 다음 `.then()`에서 `console.log('and then');`이 실행됩니다.

### 최종 출력 순서
```plaintext
kkkkkkkkkkkkkkk
1
2
3
z Promise { <pending> }
4
a 1
hmm
b 1
in z
haha
and then
```

이 순서는 JavaScript의 비동기 처리 메커니즘, 특히 `async/await`와 프로미스의 행동 방식을 반영합니다. 호출 스택이 비어 있을 때, 마이크로 태스크 큐(여기서는 `async/await`에서 발생한 프로미스)와 매크로 태스크 큐의 작업이 처리됩니다.

댓글 영역