11
22# 프라미스 체이닝
33
4- < info:callbacks > 에서 언급한 문제를 다시 집어봅시다. 스크립트를 불러오는 것과 같이 순차적으로 처리해야 하는 비동기 작업이 여러 개 있다고 가정해 봅시다. 이런 상황을 어떻게 하면 코드로 잘 풀어낼 수 있을까요?
4+ < info:callbacks > 챕터에서 언급한 문제를 다시 집어봅시다. 스크립트를 불러오는 것과 같이 순차적으로 처리해야 하는 비동기 작업이 여러 개 있다고 가정해 봅시다. 어떻게 해야 이런 상황을 코드로 풀어낼 수 있을까요?
55
66프라미스를 사용하면 여러 가지 해결책을 만들 수 있습니다.
77
@@ -35,20 +35,20 @@ new Promise(function(resolve, reject) {
3535프라미스 체이닝은 ` result ` 가 ` .then ` 핸들러의 체인(사슬)을 통해 전달된다는 점에서 착안한 아이디어입니다.
3636
3737위 예시는 아래와 같은 순서로 실행됩니다.
38- 1 . 1초 후 최초 프라미스가 이행됩니다, -- ` (*) `
39- 2 . 이후 ` .then ` 핸들러가 호출됩니다. --` (**) `
38+ 1 . 1초 후 최초 프라미스가 이행됩니다. -- ` (*) `
39+ 2 . 이후 첫번째 ` .then ` 핸들러가 호출됩니다. --` (**) `
40403 . 2에서 반환한 값은 다음 ` .then ` 핸들러에 전달됩니다. -- ` (***) `
41414 . 이런 과정이 계속 이어집니다.
4242
4343` result ` 가 핸들러 체인을 따라 전달되므로, ` alert ` 창엔 ` 1 ` , ` 2 ` , ` 4 ` 가 순서대로 출력됩니다.
4444
4545![ ] ( promise-then-chain.svg )
4646
47- 이렇게 프라미스 체이닝이 가능한 이유는 ` promise.then ` 을 호출하면 프라미스가 반환되기 때문입니다. 프라미스가 반환되기 때문에 ` .then ` 을 호출할 수 있습니다.
47+ 프라미스 체이닝이 가능한 이유는 ` promise.then ` 을 호출하면 프라미스가 반환되기 때문입니다. 반환된 프라미스엔 당연히 ` .then ` 을 호출할 수 있습니다.
4848
49- 핸들러가 값을 반환할 땐, 이 값이 프라미스의 ` result ` 가 됩니다. 따라서 다음 ` .then ` 은 이 값을 이용해 호출됩니다.
49+ 한편 핸들러가 값을 반환할 때엔 이 값이 프라미스의 ` result ` 가 됩니다. 따라서 다음 ` .then ` 은 이 값을 이용해 호출됩니다.
5050
51- ** 초보자는 프라미스 하나에 ` .then ` 을 여러 개 추가한 후, 이를 체이닝이라고 착각합니다 . 하지만 이는 체이닝이 아닙니다.**
51+ ** 초보자는 프라미스 하나에 ` .then ` 을 여러 개 추가한 후, 이를 체이닝이라고 착각하는 경우가 있습니다 . 하지만 이는 체이닝이 아닙니다.**
5252
5353예시:
5454``` js run
@@ -72,21 +72,21 @@ promise.then(function(result) {
7272});
7373```
7474
75- 위 예시에선 프라미스 하나에 여러 개의 핸들러를 등록했습니다 . 이 핸들러들은 ` result ` 를 순차적으로 전달하지 않고, 독립적으로 처리합니다.
75+ 예시의 프라미스는 하나인데 여기에 등록된 핸들러는 여러 개 입니다 . 이 핸들러들은 ` result ` 를 순차적으로 전달하지 않고 독립적으로 처리합니다.
7676
77- 그림으로 표현하면 다음과 같습니다( 프라미스 체이닝을 묘사한 위 그림과 비교해 보세요) .
77+ 그림으로 표현하면 다음과 같습니다. 프라미스 체이닝을 묘사한 위 그림과 비교해 보세요.
7878
7979![ ] ( promise-then-many.svg )
8080
81- 동일한 프라미스에 등록된 ` .then ` 전체는 동일한 결과(프라미스의 ` result ` )를 받습니다. 따라서 위 예시를 실행하면 얼럿 창엔 전부 ` 1 ` 이 출력됩니다.
81+ 동일한 프라미스에 등록된 ` .then ` 모두는 동일한 결과(프라미스의 ` result ` )를 받습니다. 따라서 위 예시를 실행하면 얼럿 창엔 전부 ` 1 ` 이 출력됩니다.
8282
83- 이런 식으로 한 프라미스에 여러 개의 핸들러를 등록해서 사용하는 경우는 거의 없습니다. 프라미스 체이닝이 더 많이 쓰이죠 .
83+ 이런 식으로 한 프라미스에 여러 개의 핸들러를 등록해서 사용하는 경우는 거의 없습니다. 프라미스는 주로 체이닝을 해서 씁니다 .
8484
8585## 프라미스 반환하기
8686
8787` .then(handler) ` 에 사용된 핸들러가 프라미스를 생성하거나 반환하는 경우도 있습니다.
8888
89- 이런 경우에 이어지는 핸들러는 프라미스가 처리될 때까지 기다리다가 처리가 완료되면 그 결과를 받습니다.
89+ 이 경우 이어지는 핸들러는 프라미스가 처리될 때까지 기다리다가 처리가 완료되면 그 결과를 받습니다.
9090
9191예시:
9292
@@ -121,15 +121,15 @@ new Promise(function(resolve, reject) {
121121```
122122
123123예시에서 첫 번째 ` .then ` 은 ` 1 ` 을 출력하고 ` new Promise(…) ` 를 반환(` (*) ` )합니다.
124- 1초 후 이 프라미스가 이행되고 그 결과(` resolve ` 의 인수인 ` result * 2 ` )는 두 번째 ` .then ` 으로 전달됩니다. 두 번째 핸들러(` (**) ` )는 ` 2 ` 를 출력하고 동일한 과정을 반복합니다 .
124+ 1초 후 이 프라미스가 이행되고 그 결과(` resolve ` 의 인수인 ` result * 2 ` )는 두 번째 ` .then ` 으로 전달됩니다. 두 번째 핸들러(` (**) ` )는 ` 2 ` 를 출력하고 동일한 과정이 반복됩니다 .
125125
126126따라서 얼럿 창엔 이전 예시와 동일하게 1, 2, 4가 차례대로 출력됩니다. 다만 얼럿 창 사이에 1초의 딜레이가 생깁니다.
127127
128- 이렇게 프라미스를 반환하는 것도 비동기 작업 체인을 만들 수 있게 합니다 .
128+ 이렇게 핸들러 안에서 프라미스를 반환하는 것도 비동기 작업 체이닝을 가능하게 해줍니다 .
129129
130- ## 예제: loadScript
130+ ## loadScript 예시 개선하기
131131
132- 위에서 배운 기능을 사용해 [ 이전 챕터] ( info:promise-basics#loadscript ) 에서 프라미스를 사용해 정의한 ` loadScript ` (스크립트를 순차적으로 불러줌)를 다시 작성해봅시다 .
132+ 지금까지 배운 기능을 사용해 [ 이전 챕터] ( info:promise-basics#loadscript ) 에서 프라미스를 사용해 정의한 ` loadScript ` (스크립트를 순차적으로 불러줌)를 개선해 봅시다 .
133133
134134``` js run
135135loadScript (" /article/promise-chaining/one.js" )
@@ -148,14 +148,14 @@ loadScript("/article/promise-chaining/one.js")
148148 });
149149```
150150
151- 화살표 함수를 사용해 코드를 줄이는 것도 가능합니다 .
151+ 화살표 함수를 사용하면 다음과 같이 코드를 줄일수도 있습니다 .
152152
153153``` js run
154154loadScript (" /article/promise-chaining/one.js" )
155155 .then (script => loadScript (" /article/promise-chaining/two.js" ))
156156 .then (script => loadScript (" /article/promise-chaining/three.js" ))
157157 .then (script => {
158- // 스크립트를 정상적으로 불러왔기 때문에, 스크립트 내의 함수를 호출할 수 있습니다.
158+ // 스크립트를 정상적으로 불러왔기 때문에 스크립트 내의 함수를 호출할 수 있습니다.
159159 one ();
160160 two ();
161161 three ();
@@ -165,7 +165,7 @@ loadScript("/article/promise-chaining/one.js")
165165
166166` loadScript ` 를 호출할 때마다 프라미스가 반환되고 다음 ` .then ` 은 이 프라미스가 이행되었을 때 실행됩니다. 이후에 다음 스크립트를 로딩하기 위한 초기화가 진행됩니다. 스크립트는 이런 과정을 거쳐 순차적으로 로드됩니다.
167167
168- 체인에 더 많은 비동기 동작을 추가할 수도 있습니다. 추가 작업이 많아져도 코드가 오른쪽으로 길어지지 않고, 아래로만 증가한다는 점에 주목해 주시기 바랍니다. '멸망'의 피라미드가 만들어지지 않습니다.
168+ 체인에 더 많은 비동기 동작을 추가할 수도 있는데, 추가 작업이 많아져도 코드가 오른쪽으로 길어지지 않고 아래로만 증가해서 '멸망'의 피라미드가 만들어지지 않습니다.
169169
170170한편, 아래와 같이 각 ` loadScript ` 에 ` .then ` 을 바로 붙일 수도 있습니다.
171171
@@ -190,11 +190,11 @@ loadScript("/article/promise-chaining/one.js").then(script1 => {
190190
191191
192192```` smart header="thenable"
193- 핸들러는 프라미스가 아닌 `thenable`이라 불리는 객체를 반환하기도 합니다. 메서드 `.then`을 가진 객체는 모두 `thenable`객체라고 부르는데, 이 객체는 프라미스와 같은 방식으로 처리됩니다.
193+ 핸들러는 프라미스가 아닌 `thenable`이라 불리는 객체를 반환하기도 합니다. `.then`이라는 메서드를 가진 객체는 모두 `thenable`객체라고 부르는데, 이 객체는 프라미스와 같은 방식으로 처리됩니다.
194194
195- 'thenable' 객체에 대한 아이디어는 서드파티 라이브러리가 '프라미스와 호환 가능한' 자체 객체를 구현할 수 있다는 점에서 나왔습니다. 이 객체들엔 자체 확장 메서드가 구현되어 있겠지만, `.then`이 있기 때문에 네이티브 프라미스와도 호환 가능합니다.
195+ 'thenable' 객체에 대한 아이디어는 서드파티 라이브러리가 '프라미스와 호환 가능한' 자체 객체를 구현할 수 있다는 점에서 나왔습니다. 이 객체들엔 자체 확장 메서드가 구현되어 있겠지만 `.then`이 있기 때문에 네이티브 프라미스와도 호환 가능합니다.
196196
197- 아래는 thenable 객체에 대한 예시입니다.
197+ 아래는 thenable 객체 예시입니다.
198198
199199```js run
200200class Thenable {
@@ -233,11 +233,11 @@ new Promise(resolve => resolve(1))
233233let promise = fetch (url);
234234```
235235
236- 위 코드를 실행하면 ` url ` 에 네트워크 요청을 보내고 프라미스를 반환합니다. 원격 서버가 헤더와 함께 응답을 보내면, 프라미스는 ` response ` 객체와 함께 이행됩니다. 그런데 * response 전체가 완전히 다운로드되기 전* 에 이행 상태가 되어버리죠 .
236+ 위 코드를 실행하면 ` url ` 에 네트워크 요청을 보내고 프라미스를 반환합니다. 원격 서버가 헤더와 함께 응답을 보내면, 프라미스는 ` response ` 객체와 함께 이행됩니다. 그런데 이때 * response 전체가 완전히 다운로드되기 전* 에 프라미스는 이행 상태가 되어버립니다 .
237237
238- 응답 전체를 읽으려면 메서드 ` response.text() ` 를 호출해야 합니다. ` response.text() ` 는 원격 서버에서 전송한 텍스트 전체가 다운로드되면, 이 텍스트를 ` result ` 값으로 갖는 이행된 프라미스를 반환합니다.
238+ 응답이 완전히 종료되고, 응답 전체를 읽으려면 메서드 ` response.text() ` 를 호출해야 합니다. ` response.text() ` 는 원격 서버에서 전송한 텍스트 전체가 다운로드되면, 이 텍스트를 ` result ` 값으로 갖는 이행된 프라미스를 반환합니다.
239239
240- 아래 코드를 실행하면 ` user.json ` 에 요청을 보내고, 서버에서 해당 텍스트를 불러옵니다.
240+ 아래 코드를 실행하면 ` user.json ` 에 요청이 가고 서버에서 해당 텍스트를 불러옵니다.
241241
242242``` js run
243243fetch (' /article/promise-chaining/user.json' )
@@ -253,7 +253,7 @@ fetch('/article/promise-chaining/user.json')
253253 });
254254```
255255
256- 그런데 메서드 ` response.json() ` 를 쓰면 원격에서 받아온 데이터를 읽고, JSON으로 파싱할 수 있습니다. 예시엔 이 메서드가 더 적합하므로 기존에 작성한 코드를 약간 변경해 보겠습니다.
256+ 그런데 메서드 ` response.json() ` 를 쓰면 원격에서 받아온 데이터를 읽고 JSON으로 파싱할 수 있습니다. 예시엔 이 메서드가 더 적합하므로 기존에 작성한 코드를 약간 변경해 보겠습니다.
257257
258258화살표 함수도 함께 써서 코드를 간결하게 해보겠습니다.
259259
@@ -288,11 +288,11 @@ fetch('/article/promise-chaining/user.json')
288288 });
289289```
290290
291- 코드는 주석에 적은 대로 잘 동작합니다. 그런데 위 코드엔 프로미스를 다루는데 서툰 개발자가 자주 저지르는 잠재적 문제가 내재돼 있습니다.
291+ 코드는 주석에 적은 대로 잘 동작합니다. 그런데 위 코드엔 프라미스를 다루는데 서툰 개발자가 자주 저지르는 잠재적 문제가 내재돼 있습니다.
292292
293293` (*) ` 로 표시한 줄을 봅시다. 만약 아바타가 잠깐 보였다가 사라진 * 이후에* 무언가를 하고 싶으면 어떻게 해야 할까요? 사용자 정보를 수정할 수 있게 해주는 폼을 보여주는 것 같은 작업을 추가하는 경우같이 말이죠. 지금으로선 방법이 없습니다.
294294
295- 체인을 확장할 수 있도록 만들려면, 아바타가 사라질 때 이행 프라미스를 반환해 줘야 합니다.
295+ 체인을 확장할 수 있도록 만들려면 아바타가 사라질 때 이행 프라미스를 반환해 줘야 합니다.
296296
297297아래와 같이 말이죠.
298298
@@ -320,7 +320,7 @@ fetch('/article/promise-chaining/user.json')
320320 .then (githubUser => alert (` Finished showing ${ githubUser .name } ` ));
321321```
322322
323- ` (*) ` 로 표시한 곳의 ` .then ` 핸들러는 이제 ` setTimeout ` 안의 ` resolve(githubUser) ` 를 호출했을 때(` (**) ` ) 만 처리상태가 되는 ` new Promise ` 를 반환합니다. 체인의 다음 ` .then ` 은 이를 기다리죠 .
323+ ` (*) ` 로 표시한 곳의 ` .then ` 핸들러는 이제 ` setTimeout ` 안의 ` resolve(githubUser) ` 를 호출했을 때(` (**) ` ) 만 처리상태가 되는 ` new Promise ` 를 반환합니다. 체인의 다음 ` .then ` 은 이를 기다립니다 .
324324
325325비동기 동작은 항상 프라미스를 반환하도록 하는 것이 좋습니다. 지금은 체인을 확장할 계획이 없더라도 이렇게 구현해 놓으면 나중에 체인 확장이 필요한 경우 손쉽게 체인을 확장할 수 있습니다.
326326
@@ -361,7 +361,7 @@ loadJson('/article/promise-chaining/user.json')
361361
362362## 요약
363363
364- ` .then ` 또는 ` catch/ finally ` 핸들러(어떤 경우도 상관없음)가 프라미스를 반환하면, 나머지 체인은 프라미스가 처리될 때까지 대기합니다. 처리가 완료되면 프라미스의 ` result ` (값 또는 에러)가 다음 체인으로 전달됩니다.
364+ ` .then ` 또는 ` . catch` , ` . finally` 의 핸들러(어떤 경우도 상관없음)가 프라미스를 반환하면, 나머지 체인은 프라미스가 처리될 때까지 대기합니다. 처리가 완료되면 프라미스의 ` result ` (값 또는 에러)가 다음 체인으로 전달됩니다.
365365
366366이를 그림으로 나타내면 아래와 같습니다.
367367
0 commit comments