Skip to content

Commit 99042a4

Browse files
committed
[JS_Promise]
1 parent 0da333c commit 99042a4

2 files changed

Lines changed: 238 additions & 0 deletions

File tree

Modern JS/JS_Promise.md

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
# JS Promise
2+
3+
- [JS Promise](#js-promise)
4+
- [Promise 생성](#promise-생성)
5+
- [async await](#async-await)
6+
- [마이크로태스크](#마이크로태스크)
7+
8+
## Promise 생성
9+
10+
```js
11+
const p1 = new Promsie((resolve, reject) => {
12+
// resolve() // p1 객체는 이행됨(fulfilled)
13+
// reject() // p1 객체는 거부됨(rejected)
14+
// exception 발생 => 거부됨
15+
}); // 대기중(pending) 상태 return Promise
16+
const p2 = Promise.reject(); // return Promise
17+
const p3 = Promise.resolve(); // reeturn Promise
18+
```
19+
20+
- new 키워드를 사용해서 프로미스를 생성하는 순간 생성자의 입력함수가 실행
21+
- 만약 API 용청을 보내는 비동기 코드가 있다면 **프로미스가 생성되는 순간에** 요청을 보낸다.
22+
23+
```js
24+
const p1 = Promise.resolve(123); // return Promise
25+
Promise.resolve(p1) === p1; // Promise.resolve 함수에 프로미스가 입력되면 그 자신이 반환된다.
26+
```
27+
28+
```js
29+
requestData().then(onResolve, onReject); // 프로미스가 처리됨 상태가 되면 onResolve 함수가 호출 되고, 거부됨 상태가 되면 onRejct 함수가 호출
30+
Promise.resolve(123).then((data) => console.log(data));
31+
Promise.reject(123).then(null, (error) => console.log(error));
32+
```
33+
34+
- 결과적으로 `then` 메서드는 **항상 프로미스를 반환한다.**
35+
- 프로미스가 `거부됨 상태인` 경우에는 **onReject 함수가 존재하는 then을 만날때까지 이동한다.**
36+
37+
```js
38+
Promise.reject(data)
39+
.then((then1) => console.log("then1", then1))
40+
.then((then2) => console.log("then2", then2))
41+
.then((then3) => console.log("then3", then3), (then4) => console.log("then4", then4));
42+
.then((then5) => console.log("then5", then5), (then6) => console.log("then6", then6));
43+
```
44+
45+
- 거부된 상태인 프로미스는 처음으로 만나는 onReject 함수를 호출하므로 빈 코드 블록은 생략 된다.
46+
- onReject 함수는 undefined를 결과로 가지면서 이행됨 상태인 프로미스를 생성한다.
47+
- 따라서 then5가 출력된다.
48+
- result: then4 ~ , then5 ~
49+
50+
```js
51+
Promise.reject(data).catch((error) => console.log("error", error)); // catch 메서드는 then 메서드의 onReject 함수와 같은 역할을 한다.
52+
Promise.reject(data)
53+
.catch((error) => error); // catch 메서드도 새로운 프로미스를 반환한다.
54+
.then((then) => console.log("then", then))
55+
```
56+
57+
```js
58+
new Promise(function (resolve, reject) {
59+
setTimeout(() => {
60+
throw new Error("에러 발생!");
61+
}, 1000);
62+
}).catch(alert);
63+
```
64+
65+
- `.catch는` 트리거 되지 않는다.
66+
- 암시적 try, .. catch가 함수 코드를 감사고 있으므로 모든 동기적 에러는 암시적 try, ...catch에서 처리 된다.
67+
- 하지만 여기에서 에러는 excutor(실행자, 실행 함수)가 실행되는 동안이 아니라 나중에 발생한다.
68+
- **따라서 프로미스는 에러를 처리할 수 없다.**
69+
- 하지만 `reject로` 호출했을 때는 `catch로` 전달이 된다.
70+
71+
```js
72+
requestData()
73+
.then((data) => {})
74+
.catch((error) => {})
75+
.finally(() => {});
76+
```
77+
78+
- finally는 처리됨 상태인 프로미스의 데이터를 건드리지 않고 추가 작업을 할 때 유용하게 쓰인다.
79+
- requestData 함수의 반환값은 finally 메서드 호출 이전의 프로미스다.
80+
81+
```js
82+
Promise.all([requestData(), requestData2()]).then(([data1, data2]) => {
83+
console.log("data1", data1);
84+
console.log("data2", data2);
85+
}); // return Promise
86+
```
87+
88+
- `Promise.all` 함수가 반화하는 프로미스는 입력된 **모든 프로미스가 처리됨 상태가** 되어야 처림됨 상태가 된다.
89+
- 하나라도 거부됨 상태가 된다면 즉시, Promise.all 함수가 반환하는 프로미스도 거부됨 상태가 된다.
90+
> fetch를 사용해 호출 여러 개를 만들면, 그중 하나가 실패하더라도 호출은 계속 일어납니다.
91+
> 렇더라도 Promise.all은 다른 호출을 더는 신경 쓰지 않습니다. 프라미스가 처리되긴 하겠지만 그 결과는 무시됩니다.
92+
93+
```js
94+
Promise.race([
95+
requestData(),
96+
new Promise((_, reject) => setTimeout(reject, 3000)),
97+
])
98+
.then((data) => console.log(data))
99+
.catch((error) => console.log(error));
100+
```
101+
102+
- `Promise.race는` 여러 개의 프로미스 중에서 가장 빨리 처리된 프로미스를 반환하는 함수이다.
103+
- requestData 함수가 3초 안에 데이터를 받으면 then 메서드가 호출, 그렇지 않으면 catch 메서드 호출
104+
105+
```js
106+
function requestData(params) {
107+
const p = Promise.resolve(10); // 생성되자 마자 실행 => new reslovePromise(10)
108+
p.then(() => 20); // then 메서드는 기존 객체를 수정하지 않고, 새로운 프로미스를 반환한다. => new Thenalbe(()=> 20)
109+
return p;
110+
}
111+
requestData().then((v) => {
112+
console.log("v", v); // 10
113+
});
114+
```
115+
116+
- 프로미스는 `불변 객체다`.
117+
118+
```js
119+
function requestData() {
120+
return Promise.resolve(10).then((v) => {
121+
return 20;
122+
});
123+
}
124+
requestData().then((v) => {
125+
console.log("v", v); // 20
126+
});
127+
```
128+
129+
## async await
130+
131+
```js
132+
async function getData() {
133+
return 123;
134+
} // return Promise
135+
getData().then((data) => console.log("data", data)); // 123
136+
```
137+
138+
- `async는` Promise 객체로 변환하여 리턴해주는 키워드이다.
139+
140+
```js
141+
async function getData() {
142+
return Promise.resolve(123); // 프로미스의 then 메서드와 마찬가지로 async await 함수 내부에서 반환하는 값이 프로미스라면 그 객체를 그대로 반환
143+
}
144+
getData().then((data) => console.log(data)); // 123
145+
```
146+
147+
```js
148+
function requestData(value) {
149+
return new Promise((resolve) =>
150+
setTimeout(() => {
151+
console.log("requestData", value);
152+
resolve(value);
153+
}, 100)
154+
);
155+
}
156+
async function getData() {
157+
const data1 = await requestData(10); // 프로미스가 처리됨 상태가 될 때까지 다음 코드를 실행하지 않는다. => .then 역할
158+
const data2 = await requestData(20);
159+
console.log("data1", data1);
160+
console.log("data2", data2);
161+
return [data1, data2];
162+
}
163+
getData(); // Promise
164+
```
165+
166+
```js
167+
async function getData() {
168+
const p1 = asyncFunc1();
169+
const p2 = asyncFunc2();
170+
// 두개의 프로미스가 생성되고 각자의 비동기 코드가 실행된다.
171+
const data1 = await p1; // await으로 프로미스가 생성된 후 기다리기 때문에 두 개의 비동기 함수가 병렬로 처리된다.
172+
const data2 = await p2;
173+
}
174+
async function getData() {
175+
const [data1, data2] = await Promise.all([asyncFunc1(), asyncFunc2()]);
176+
}
177+
```
178+
179+
```js
180+
class TEX {
181+
then(resolve, reject) {
182+
setTimeout(() => resolve(1234), 10000);
183+
}
184+
}
185+
async function asyncFunc() {
186+
const result = await new TEX();
187+
console.log("result", result); // 1234
188+
}
189+
```
190+
191+
- `Thenable은` 프로미스처럼 동작하는 객체다.
192+
- async await은 ES6의 프로미스가 아니더라도 then 메서드를 가진 객체를 **프로미스처럼 취급한다.**
193+
- 프로미스가 아니더라도 then 메서드르 가진 객체를 Thenable이라고 부른다.
194+
195+
## 마이크로태스크
196+
197+
- 프로미스 핸들러 `.then/catch/finally는` 항상 비동기적으로 실행된다.
198+
> 프라미스가 즉시 이행되더라도 `.then/catch/finally` 아래에 있는 코드는 이 핸들러들이 실행되기 전에 실행됩니다.
199+
200+
```js
201+
let promise = Promise.resolve();
202+
203+
promise.then(() => console.log("프로미스 성공!"));
204+
205+
console.log("코드 종료"); // 이 로그가 가장 먼저 나타난다.
206+
```
207+
208+
> 요약하자면, 어떤 프라미스가 준비되었을 때 이 프라미스의 `.then/catch/finally` 핸들러가 마이크로태스크큐에 들어간다고 생각하시면 됩니다.
209+
>
210+
> 이때 핸들러들은 여전히 실행되지 않습니다. `현재 코드에서 자유로운 상태가 되었을 때에서야` 자바스크립트 엔진은 큐에서 작업을 꺼내 실행합니다.
211+
212+
> 비동기 작업을 처리하려면 적절한 관리가 필요합니다.
213+
>
214+
> 이를 위해 ECMA에선 PromiseJobs라는 내부 큐(internal queue)를 명시합니다.
215+
>
216+
> V8 엔진에선 이를 '마이크로태스크 큐(microtask queue)'라고 부르기 때문에 이 용어가 좀 더 선호됩니다.
217+
218+
- JS_Engine 참고
219+
220+
```js
221+
let promise = Promise.reject(new Error("프로미스 실패!"));
222+
setTimeout(() => promise.catch((err) => alert("잡았다!")), 1000);
223+
224+
// Error: 프로미스 실패!
225+
window.addEventListener("unhandledrejection", (event) => alert(event.reason));
226+
```
227+
228+
- `unhandledrejection은` 마이크로태스크 큐에 있는 작업 모두가 완료되었을 때 생성된다.
229+
- `.catch`같이 `에러 헨들러가` 없다면 마이크로태스크 큐는 계속해서 에러 핸들러를 처리하고 요청을 하기 때문에 뒤에있는 테스크가 쌓이게 된다.
230+
- 그것을 맞기위해 `unhandlerrejection을` `트리거` 하여 에러를 처리하도록 요청한다.
231+
- 위 예시를 실행하면 setTimeout을 사용해 추가한 `.catch` 역시 트리거 된다.
232+
- 다만 `.catch는` `unhandledrejection이` 발생한 이후에 트리거 되므로 `프로미스 실패!가 출력된다.`

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@
6161
- super 키워드와 [[HomeObject]]
6262
- instanceof
6363

64+
- [JS Promise](./Modern%20JS/../Modern%20JS/JS_Promise.md)
65+
66+
- Promise 생성
67+
- async await
68+
- 마이크로태스크
69+
6470
**[위로](#javascript)**
6571

6672
## ES2015

0 commit comments

Comments
 (0)