Skip to content

Commit 1896aef

Browse files
committed
update post
1 parent b1ae38f commit 1896aef

File tree

9 files changed

+306
-28
lines changed

9 files changed

+306
-28
lines changed

content/posts/자원/JavaScript/Javascript.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ tags:
44
- web
55
- javascript
66
createdAt: 2025-04-12 09:09:33
7-
modifiedAt: 2025-04-19 18:43:43
7+
modifiedAt: 2025-04-19 20:48:09
88
publish: 자원/JavaScript
99
related: ""
1010
series: ""
@@ -29,3 +29,4 @@ series: ""
2929
- [[`this`키워드`]]
3030
- [[프로토타입(Prototype)과 프로토타입 상속]]
3131
- [[Javascript는 어떻게 비동기 처리가 가능한 것인가]]
32+
- [[Javascript에서의 비동기 함수]]
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
tags:
3+
- resource
4+
- javascript
5+
createdAt: 2025-04-19 18:43:45
6+
modifiedAt: 2025-04-19 21:35:43
7+
publish: 자원/JavaScript
8+
related: ""
9+
series: ""
10+
---
11+
12+
# Javascript는 어떻게 비동기 처리가 가능한 것인가
13+
14+
자바스크립트 엔진 자체는 싱글 스레드 기반으로 동작하여 한번에 하나의 작업만 처리할 수 있는 [[콜 스택(Call Stack)이란 무엇인가|콜 스택]] 을 갖는다. 하지만 자바스크립트가 실행되는 환경(웹 브라우저나 Node.js)은 자바스크립트 엔진 외에도 비동기 작업을 처리하는 별도의 API(Web API 또는 C++API)와 여러개의 큐(Queue), 그리고 이들을 조율하는 **이벤트 루프(Event Loop)**를 제공한다. 이 구조 덕분에 싱글 스레드 입에도 불구하고 논블로킹(none-blocking) 방식으로 비동기 처리가 가능하다
15+
16+
참고: [[Javascript에서의 비동기 함수]]
17+
18+
## 이벤트 루프
19+
20+
자바스크립트의 비동기 프로그래밍 모델의 핵심 메커니즘
21+
22+
![eventloop](_assets/attachments/eventloop.gif)
23+
24+
- 콜 스택(Call Stack): 현재 실행중인 함수의 실행 컨텍스트를 저장하는 LIFO 구조의 스택이다. 동기적인 코드 실행을 담당한다.
25+
- Web API/Node.js API: `setTimeout`,`setInterval`,DOM 이벤트 리스터, `fetch`(네트워크 요청), 파일 I/O등 비동기 작업을 처리하는 환경 제공 기능이다. 이 작업들은 자바스크립트 엔진의 메인 스레드 밖에서 수행된다.
26+
- 태스크 큐(Task Queue/Macrotask Queue): Web API등에서 완료된 비동기 작업의 [[콜백 함수(Callback Function)란 무엇인가|콜백 함수]]들이 대기하는 FIFO구조의 큐이다. `setTimeout`,`setInterval`콜백, I/O 완료 콜백, UI렌더링 작업 등이 여기에 해당한다.
27+
- 마이크로태스크 큐(Microtask Queue): 태스크 큐와 유사하지만, 더 높은 우선순위를 가진다. `Promise콜백 함수(Callback Function)이란 무엇인가``.then()`,`.catch()`,`.finally()`콜백, `queueMicrotask()`,`MutationObserver`콜백 등이 여기에 해당한다.
28+
29+
- 이벤트 루프(Event Loop): 콜 스택과 큐들을 지속적으로 감시하는 프로세스
30+
1. 콜 스택 확인: 콜 스택이 비어있는지 확인한다.
31+
2. 마이크로태스크 큐 처리: 콜 스택이 비어 있다면, 마이크로태스크 큐에 있는 모든 콜백 함수를 순서대로 꺼내어 콜스택에 넣고 실핸한다. 마이크로태스크 실행 중 새로운 마이크로태스크가 추가되면 이 역시 현재 루프 주기 내에서 모두 처리된다.
32+
3. 매크로태스크 큐 처리:마이크로태스크 큐가 비워니 후 (그리고 필요한 UI 렌더링 등이 수행된 후), 매크로태스크 큐에서 하나의 콜백 함수를 꺼내어 콜 스택에 넣고 실핸한다.
33+
4. 위 과정을 계속 반복한다.
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
---
2+
tags:
3+
- resource
4+
- javascript
5+
createdAt: 2025-04-19 20:47:13
6+
modifiedAt: 2025-04-19 21:35:38
7+
publish: 자원/JavaScript
8+
related: ""
9+
series: ""
10+
---
11+
12+
# Javascript에서의 비동기 함수
13+
14+
자바스크립트는 기본적으로 '단일 스레드'언어이다. 이는 한 번에 하나의 작업만 수행할 수 있다는 의미이다. 그러나 웹 애플리케이션에서는 데이터 가져오기, 파일 읽기/쓰기 등 시간이 오래 걸리는 작업이 많이 있다. 이러한 **작업을 동기적으로 처리한다면, 작업이 완료될 때까지 다른 모든 코드의 실행이 중단**된다.
15+
16+
비동기 프로그래밍은 이런 문제를 해결한다. 비동기 작업은 메인 실행 스레드를 차단하지 않고 백그라운드에서 실행되며, 작업이 완료되면 결과를 반환한다.
17+
18+
> [!caution]
19+
> "단일 스레드" 라는것은 어디까지나 코드를 읽고 해석하고 실행시키는 작업만 해당된다. 자바스크립트 엔진은 실행 자체는 Node.js 나 브라우저에 업무를 위임하게 되는데 Node.js 나 브라우저는 멀티 스레드로 컴퓨팅하여 작업을 처리한다.
20+
21+
## 비동기 처리 방식의 발전
22+
23+
### 콜백 함수(Callbacks)
24+
25+
초기 자바스크립트에서는 비동기 처리를 위해 콜백 함수를 사용했다. **콜백 함수는 다른 함수에 인수로 전달되어, 그 함수 내부에서 나중에 호출**되는 함수를 의미한다. 비동기 처리에서는 특정 작업(예: 타이머 완료, 데이터 로딩 완료, 이벤트 발생)이 끝났을 때 실행될 로직을 콜백 함수 형태로 전달하는 방식으로 주로 사용된다. 비동기 작업을 시작하는 함수는 즉시 반환되고, 작업이 완료되면 미리 등록된 콜백 함수가 호출되어 결과를 처리하거나 다음 단계를 진행한다.
26+
27+
```js
28+
function fetchData(callback) {
29+
setTimeout(() => {
30+
const data = "데이터가 도착했습니다";
31+
callback(data);
32+
}, 2000);
33+
}
34+
35+
fetchData((data) => {
36+
console.log(data); // 2초 후 "데이터가 도착했습니다" 출력
37+
});
38+
```
39+
40+
#### 콜백 지옥(Callback Hell)
41+
42+
여러 개의 비동기 작업을 순차적으로 처리해야 할 때 콜백 함수가 계속해서 중첩되어 코드의 들여쓰기 수준이 깊어지고 가독성이 극도로 나빠지는 상황을 말한다.
43+
44+
콜백 지옥은 콜백 패턴의 한계를 보여주는 대표적인 예시이며 이러한 문제를 해결하기 위해 `promise``async/await`같은 더 나은 비동기 처리 패턴이 등장하게 되었다.
45+
46+
##### 문제점
47+
48+
1. 가독성 저하: 코드가 오른쪽으로 계속 길어져 전체 로직을 파악하기 어렵다.
49+
2. 에러 처리의 어려움: 각 콜백 단계마다 에러 처리를 별도로 해주어야 하며, 에러가 발생했을 때 어디서 문제가 생겼는지 추적하기 어렵다.
50+
3. 유지보수 어려움: 코드 수정이나 기능 추가 시 복잡한 중첩 구조 때문에 실수를 유발하기 쉽다.
51+
52+
```js
53+
asyncTask1(
54+
function (result1) {
55+
asyncTask2(
56+
result1,
57+
function (result2) {
58+
asyncTask3(
59+
result2,
60+
function (result3) {
61+
//... 계속 중첩...
62+
asyncTaskN(
63+
resultN_1,
64+
function (resultN) {
65+
// 최종 결과 처리
66+
},
67+
function (errorN) {
68+
// 에러 처리 N
69+
},
70+
);
71+
},
72+
function (error3) {
73+
// 에러 처리 3
74+
},
75+
);
76+
},
77+
function (error2) {
78+
// 에러 처리 2
79+
},
80+
);
81+
},
82+
function (error1) {
83+
// 에러 처리 1
84+
},
85+
);
86+
```
87+
88+
### 프로미스(Promise)
89+
90+
프로미스는 비동기 작업의 최종 완료(또는 실패)와 그 결과 값을 나타내는 **객체** 이다.
91+
92+
프로미스는 다음 세 가지 상태중 하나를 갖는다.
93+
94+
- 대기(Pending): 초기 상태, 비동기 작업이 아직 완료되지 않음
95+
- 이행(Fullfilled): 비동기 작업이 성공적으로 완료됨. 결과 값을 가짐
96+
- 거부(Rejected): 비동기 작업이 실패함. 실패 이유(에러)를 가짐. 프로미스는 한번 상태가 결정되면(이행 또는 거부) 더 이상 변하지 않는(settled) 특징을 갖는다.
97+
98+
```js
99+
function fetchData() {
100+
return new Promise((resolve, reject) => {
101+
setTimeout(() => {
102+
const data = "데이터가 도착했습니다";
103+
resolve(data); // 성공 시 resolve 호출
104+
// 실패했다면: reject(new Error("데이터 로딩 실패"));
105+
}, 2000);
106+
});
107+
}
108+
109+
fetchData()
110+
.then((data) => {
111+
console.log(data); // "데이터가 도착했습니다"
112+
return "다음 작업을 위한 데이터";
113+
})
114+
.then((nextData) => {
115+
console.log(nextData); // "다음 작업을 위한 데이터"
116+
})
117+
.catch((error) => {
118+
console.error(error); // 오류 처리
119+
});
120+
```
121+
122+
#### 프로미스 체이닝(Promise Chaining)
123+
124+
프로미스 체이닝은 프로미스의 `.then()` 또는 `.catch()` 메서드가 항상 새로운 프로미스를 반환하는 특성을 이용하여 여러 비동기 작업을 순차적으로 연결하는 기법이다. `.then()` 핸들러는 이전 프로미스가 이행(fullfill)되면 호출되며, 그 결과 값을 받아 다음 작업을 수행하고, 또 다른 값이나 새로운 프로미스를 반환하여 체인을 이어갈 수 있다.
125+
126+
```js
127+
fetch("user.json") // 1. 사용자 정보 요청 (프로미스 반환)
128+
.then((response) => response.json()) // 2. 응답을 JSON으로 파싱 (프로미스 반환)
129+
.then((user) => fetch(`https://api.github.com/users/${user.name}`)) // 3. GitHub API 요청 (프로미스 반환)
130+
.then((githubResponse) => githubResponse.json()) // 4. GitHub 응답 파싱 (프로미스 반환)
131+
.then((githubUser) => {
132+
// 5. 최종 결과 처리
133+
console.log(githubUser.name);
134+
return githubUser; // 다음.then으로 값을 전달할 수 있음
135+
})
136+
.catch((error) => {
137+
// 에러 처리
138+
console.error("오류 발생:", error);
139+
});
140+
```
141+
142+
프로미스 체이닝은 비동기 코드의 흐름을 논리적이고 읽기 쉽게 만들어 콜백 지옥 문제를 해결하는 핵심적인 방법이다.
143+
144+
#### 프로미스 메서드
145+
146+
- `Promise.all()`: 여러 프로미스를 동시에 실행하고 모두 완료될 때까지 기다린다.
147+
- `Promise.race()`: 가장 먼저 완료되는 프로미스의 결과를 반환한다.
148+
- `Promise.allSettled()`: 모든 프로미스가 처리될 때까지 기다리고, 각 프로미스의 상태와 값을 반환한다.
149+
- `Promise.any()`: 가장 먼저 성공적으로 완료된 프로미스의 결과를 반환한다.
150+
151+
### Async/Await
152+
153+
`async`/`await` 는 프로미스를 기반으로 동작하는 비동기 처리 문법으로, 비동기 코드를 마치 동기 코드처럼 더 읽기 쉽고 간결하게 작성할 수 있도록 도와주는 문법이다.
154+
155+
- `async`함수:
156+
함수 선언 앞에 `async` 키워드를 붙여 정의한다. `async` 함수는 항상 프로미스를 반환한다. 함수 본문에서 명시적으로 프로미스를 반환하지 않더라고, 반환 값은 자동으로 `Promise.resolve()`로 감싸져 프로미스로 반환된다.
157+
158+
- `await` 연산자:
159+
`async` 함수 내부에서만 사용할 수 있다. `await` 뒤에는 주로 프로미스가 오며, 해당 프로미스가 처리될 때까지 `async`함수의 실행을 일시 중지시킨다.. 프로미스가 이행되면 `await` 표현식은 그 결과 값을 반환하고, 프로미스가 거부되면 에러를 던진다(`throw`)
160+
161+
#### `async`/`await`에서의 에러 핸들링
162+
163+
`try...catch`문을 사용하여 처리한다.
164+
165+
- `try`블록 안에 `await`를 포함한 비동기 코드를 작성한다.
166+
- 만약 `await`한 프로미스가 거부되면, 에러가 발생(throw)하고 제어 흐름은 즉시 해당 `catch`블록으로 이동한다.
167+
- `catch`블록에서는 발생한 에러 객체를 받아 로깅, 사용자 알림, 대체 로직 수행 등 필요한 에러 처리를 수행할 수 있다.
168+
169+
```js
170+
async function getUserData(userId) {
171+
try {
172+
const response = await fetch(`/api/users/${userId}`);
173+
if (!response.ok) {
174+
throw new Error(`HTTP error! status: ${response.status}`); // 명시적 에러 발생
175+
}
176+
const userData = await response.json();
177+
console.log("사용자 데이터:", userData);
178+
return userData;
179+
} catch (error) {
180+
console.error("사용자 데이터 로딩 중 오류 발생:", error);
181+
// 에러 처리 로직 (예: 기본값 반환, 에러 로깅 등)
182+
return null; // 또는 에러를 다시 던질 수도 있음: throw error;
183+
}
184+
}
185+
186+
// async 함수는 항상 프로미스를 반환합니다
187+
getUserData(123).then((result) => {
188+
console.log("최종 결과:", result);
189+
});
190+
```
191+
192+
#### 병렬처리를 위한 성능 향상
193+
194+
`async`/`await`는 코드를 간결하게 만들지만 `await`는 코드 실행을 멈추기 때문에, 서로 의존성이 없는 여러 개의 비동기 작업을 순차적으로 `await`하면 불필요하게 실행 시간이 길어질 수 있다.
195+
196+
```js
197+
// 비효율적인 순차 실행
198+
async function fetchSequential() {
199+
const result1 = await fetch("/api/data1"); // data1 완료 후 data2 시작
200+
const result2 = await fetch("/api/data2");
201+
//...
202+
}
203+
204+
// 효율적인 병렬 실행
205+
async function fetchParallel() {
206+
const [result1, result2] = await Promise.all([
207+
fetch("/api/data1"),
208+
fetch("/api/data2"),
209+
]); // data1과 data2를 동시에 요청하고 모두 완료될 때까지 기다림
210+
//...
211+
}
212+
```

public/link-map.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
{
2-
"0.inbox/`this`키워드.md": "자원/JavaScript/`this`키워드",
3-
"0.inbox/프로토타입(Prototype)과 프로토타입 상속.md": "자원/JavaScript/프로토타입(Prototype)과 프로토타입 상속",
42
"3.resource/SWEA강의/SWEA 강의 정리노트.md": "자원/SWEA 강의 정리노트/SWEA 강의 정리노트",
53
"3.resource/Javascript/변수의 선언,초기화,할당의 차이점은 무엇인가.md": "자원/JavaScript/변수의 선언,초기화,할당의 차이점은 무엇인가",
64
"3.resource/Javascript/호이스팅(Hoisting)이란 무엇인가.md": "자원/JavaScript/호이스팅(Hoisting)이란 무엇인가",
@@ -13,6 +11,10 @@
1311
"3.resource/Javascript/콜 스택(Call Stack)이란 무엇인가.md": "자원/JavaScript/콜 스택(Call Stack)이란 무엇인가",
1412
"3.resource/Javascript/클로저(Closure)란 무엇인가.md": "자원/JavaScript/클로저(Closure)란 무엇인가",
1513
"3.resource/Javascript/var,let,const의 주요 차이점은 무엇인가.md": "자원/JavaScript/var,let,const의 주요 차이점은 무엇인가",
14+
"3.resource/Javascript/`this`키워드.md": "자원/JavaScript/`this`키워드",
15+
"3.resource/Javascript/프로토타입(Prototype)과 프로토타입 상속.md": "자원/JavaScript/프로토타입(Prototype)과 프로토타입 상속",
16+
"3.resource/Javascript/Javascript에서의 비동기 함수.md": "자원/JavaScript/Javascript에서의 비동기 함수",
17+
"3.resource/Javascript/Javascript는 어떻게 비동기 처리가 가능한 것인가.md": "자원/JavaScript/Javascript는 어떻게 비동기 처리가 가능한 것인가",
1618
"3.resource/Web/동적 사이트 vs 정적사이트.md": "자원/웹개발/동적 사이트 vs 정적사이트",
1719
"3.resource/Web/HTTP(Hypertext Transfer Protocol).md": "자원/웹개발/HTTP(Hypertext Transfer Protocol)",
1820
"3.resource/Web/웹사이트는 어떻게 보여지는가-브라우저의 렌더링.md": "자원/웹개발/웹사이트는 어떻게 보여지는가-브라우저의 렌더링",

public/meta-data.json

Lines changed: 45 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,4 @@
11
[
2-
{
3-
"urlPath": "자원/JavaScript/`this`키워드",
4-
"title": "`this`키워드",
5-
"summary": "",
6-
"image": "",
7-
"tags": ["resource", "javascript"],
8-
"series": "",
9-
"createdAt": "2025-04-19 13:24:41",
10-
"modifiedAt": "2025-04-19 15:21:13",
11-
"publish": "자원/JavaScript"
12-
},
13-
{
14-
"urlPath": "자원/JavaScript/프로토타입(Prototype)과 프로토타입 상속",
15-
"title": "프로토타입(Prototype)과 프로토타입 상속",
16-
"summary": "",
17-
"image": "",
18-
"tags": ["resource", "javascript"],
19-
"series": "",
20-
"createdAt": "2025-04-19 15:21:35",
21-
"modifiedAt": "2025-04-19 18:39:55",
22-
"publish": "자원/JavaScript"
23-
},
242
{
253
"urlPath": "자원/SWEA 강의 정리노트/SWEA 강의 정리노트",
264
"title": "SWEA 강의 정리노트",
@@ -62,7 +40,7 @@
6240
"tags": ["resource", "web", "javascript"],
6341
"series": "",
6442
"createdAt": "2025-04-12 09:09:33",
65-
"modifiedAt": "2025-04-19 18:43:43",
43+
"modifiedAt": "2025-04-19 20:48:09",
6644
"publish": "자원/JavaScript"
6745
},
6846
{
@@ -153,6 +131,50 @@
153131
"modifiedAt": "2025-04-18 15:01:31",
154132
"publish": "자원/JavaScript"
155133
},
134+
{
135+
"urlPath": "자원/JavaScript/`this`키워드",
136+
"title": "`this`키워드",
137+
"summary": "",
138+
"image": "",
139+
"tags": ["resource", "javascript"],
140+
"series": "",
141+
"createdAt": "2025-04-19 13:24:41",
142+
"modifiedAt": "2025-04-19 15:21:13",
143+
"publish": "자원/JavaScript"
144+
},
145+
{
146+
"urlPath": "자원/JavaScript/프로토타입(Prototype)과 프로토타입 상속",
147+
"title": "프로토타입(Prototype)과 프로토타입 상속",
148+
"summary": "",
149+
"image": "",
150+
"tags": ["resource", "javascript"],
151+
"series": "",
152+
"createdAt": "2025-04-19 15:21:35",
153+
"modifiedAt": "2025-04-19 18:39:55",
154+
"publish": "자원/JavaScript"
155+
},
156+
{
157+
"urlPath": "자원/JavaScript/Javascript에서의 비동기 함수",
158+
"title": "Javascript에서의 비동기 함수",
159+
"summary": "",
160+
"image": "",
161+
"tags": ["resource", "javascript"],
162+
"series": "",
163+
"createdAt": "2025-04-19 20:47:13",
164+
"modifiedAt": "2025-04-19 21:35:38",
165+
"publish": "자원/JavaScript"
166+
},
167+
{
168+
"urlPath": "자원/JavaScript/Javascript는 어떻게 비동기 처리가 가능한 것인가",
169+
"title": "Javascript는 어떻게 비동기 처리가 가능한 것인가",
170+
"summary": "",
171+
"image": "",
172+
"tags": ["resource", "javascript"],
173+
"series": "",
174+
"createdAt": "2025-04-19 18:43:45",
175+
"modifiedAt": "2025-04-19 21:35:43",
176+
"publish": "자원/JavaScript"
177+
},
156178
{
157179
"urlPath": "자원/웹개발/동적 사이트 vs 정적사이트",
158180
"title": "동적 사이트 vs 정적사이트",

0 commit comments

Comments
 (0)