aboutsummaryrefslogtreecommitdiff
path: root/files/ko/learn/javascript/asynchronous
diff options
context:
space:
mode:
authorPeter Bengtsson <mail@peterbe.com>2020-12-08 14:42:17 -0500
committerPeter Bengtsson <mail@peterbe.com>2020-12-08 14:42:17 -0500
commitda78a9e329e272dedb2400b79a3bdeebff387d47 (patch)
treee6ef8aa7c43556f55ddfe031a01cf0a8fa271bfe /files/ko/learn/javascript/asynchronous
parent1109132f09d75da9a28b649c7677bb6ce07c40c0 (diff)
downloadtranslated-content-da78a9e329e272dedb2400b79a3bdeebff387d47.tar.gz
translated-content-da78a9e329e272dedb2400b79a3bdeebff387d47.tar.bz2
translated-content-da78a9e329e272dedb2400b79a3bdeebff387d47.zip
initial commit
Diffstat (limited to 'files/ko/learn/javascript/asynchronous')
-rw-r--r--files/ko/learn/javascript/asynchronous/async_await/index.html383
-rw-r--r--files/ko/learn/javascript/asynchronous/concepts/index.html159
-rw-r--r--files/ko/learn/javascript/asynchronous/index.html59
-rw-r--r--files/ko/learn/javascript/asynchronous/introducing/index.html281
-rw-r--r--files/ko/learn/javascript/asynchronous/promises/index.html588
-rw-r--r--files/ko/learn/javascript/asynchronous/timeouts_and_intervals/index.html598
6 files changed, 2068 insertions, 0 deletions
diff --git a/files/ko/learn/javascript/asynchronous/async_await/index.html b/files/ko/learn/javascript/asynchronous/async_await/index.html
new file mode 100644
index 0000000000..339a9dabdb
--- /dev/null
+++ b/files/ko/learn/javascript/asynchronous/async_await/index.html
@@ -0,0 +1,383 @@
+---
+title: Making asynchronous programming easier with async and await
+slug: Learn/JavaScript/Asynchronous/Async_await
+translation_of: Learn/JavaScript/Asynchronous/Async_await
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Promises", "Learn/JavaScript/Asynchronous/Choosing_the_right_approach", "Learn/JavaScript/Asynchronous")}}</div>
+
+<p class="summary">Javascript에 대한 최신 추가 사항은 ECMAScript 2017 JavaScript 에디션의 일부인 <a href="/en-US/docs/Web/JavaScript/Reference/Statements/async_function">async functions</a> 그리고 <code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/await">await</a></code> 키워드 입니다.(<a href="/en-US/docs/Web/JavaScript/New_in_JavaScript/ECMAScript_Next_support_in_Mozilla">ECMAScript Next support in Mozilla</a>를 참조하세요). 이러한 기능들은 Promise기반 코드를 좀 더 쓰기 쉽고 읽기 쉽게 만들어줍니다. 이 기능을 사용하면 비동기 코드를 구식 동기 코드처럼 보여주기 때문에 충분히 배울 가치가 있습니다.이번 문서에서 위의 기능을 어떻게 사용하는지 배울 것 입니다.</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Prerequisites:</th>
+ <td>Basic computer literacy, a reasonable understanding of JavaScript fundamentals, an understanding of async code in general and promises.</td>
+ </tr>
+ <tr>
+ <th scope="row">Objective:</th>
+ <td>To understand promises and how to use them.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="The_basics_of_asyncawait">The basics of async/await</h2>
+
+<p>async/await 코드는 두 가지 부분으로 나눠져있습니다.</p>
+
+<h3 id="The_async_keyword">The async keyword</h3>
+
+<p>먼저 비 동기 함수를 <a href="/en-US/docs/Web/JavaScript/Reference/Statements/async_function">async function</a>으로 만들기 위하여 function()앞에 <code>async</code> keyword를 추가합니다. async function()은 <code>await</code> 키워드가 비동기 코드를 호출할 수 있게 해주는 함수 입니다.</p>
+
+<p>브라우저의 JavaScript 콘솔에서 아래와 같이 입력해보세요. :</p>
+
+<pre class="brush: js notranslate">function hello() { return "Hello" };
+hello();</pre>
+
+<p>위의 함수는 "Hello"를 반환합니다. — 특별할게 없죠?</p>
+
+<p>그러면 함수 앞에 async 키워드를 추가하면 어떻게 될까요?? 아래처럼 작성해봅시다.:</p>
+
+<pre class="brush: js notranslate">async function hello() { return "Hello" };
+hello();</pre>
+
+<p>이제 코드가 Promise를 반환합니다. 이것이 async 기능의 특징 중 하나 입니다. — 이 키워드를 사용하면 반환받는 값은 Promise가 됩니다..</p>
+
+<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/async_function">async function expression</a>을 사용하여 아래와 같이 만들 수도 있습니다. :</p>
+
+<pre class="brush: js notranslate">let hello = async function() { return "Hello" };
+hello();</pre>
+
+<p>화살표 함수를 사용하면 아래처럼 쓸 수 있습니다. :</p>
+
+<pre class="brush: js notranslate">let hello = async () =&gt; { return "Hello" };</pre>
+
+<p>기본적으로 두 가지는 모두 같습니다.</p>
+
+<p>실제로는 fulfil Promise가 반환되기 때문에 반환된 값을 사용하기 위해선 <code>.then()</code> 블럭을 사용해야 합니다. :</p>
+
+<pre class="brush: js notranslate">hello().then((value) =&gt; console.log(value))</pre>
+
+<p>짧개 표현하면 아래와 같이 쓸 수 있습니다.</p>
+
+<pre class="brush: js notranslate">hello().then(console.log)</pre>
+
+<p>이전에 봤던 내용과 비슷하죠?.</p>
+
+<p>정리하면, <code>async</code> 를 함수와 같이 사용하면 결과를 직접 반환하는게 아니라 Promise를 반환하게 합니다. 또한 동기식 함수는 <code>await</code>사용을 위한 지원과 함께 실행되는 잠재적인 오버헤드를 피할 수 있습니다. 함수가  <code>async</code>라고 선언될 때 필요한 핸들링만 추가하면 JavaScript엔진이 우리가 만든 프로그램을 최적화 할 수 있습니다. 끝내주죠?</p>
+
+<h3 id="The_await_keyword">The await keyword</h3>
+
+<p>비동기 함수를 <a href="/en-US/docs/Web/JavaScript/Reference/Operators/await">await</a> 키워드와 함께 쓰면 그 장점이 확실히 보입니다. 이것은 어떠한 Promise기반 함수 앞에 놓을 수 있습니다. 그리고 우리의 코드의 Promise가 fulfil될 때 까지 잠시 중단하고, 결과를 반환합니다. 그리고 실행을 기다리는 다른 코드들을 중지시키지 않고 그대로 실행되게 합니다.</p>
+
+<p><code>await</code> 키워드는 웹 API를 포함하여 Promise를 반환하는 함수를 호출할 때 사용할 수 있습니다.</p>
+
+<p>여기 간단한 예가 있습니다. :</p>
+
+<pre class="brush: js notranslate">async function hello() {
+ return greeting = await Promise.resolve("Hello");
+};
+
+hello().then(alert);</pre>
+
+<p>물론 위의 예시는 그다지 쓸모있진 않습니다. 다만 어떻게 구문을 작성해야 하는지는 잘 나타내줍니다. 이제 실제 사례를 살펴봅시다.</p>
+
+<h2 id="Rewriting_promise_code_with_asyncawait">Rewriting promise code with async/await</h2>
+
+<p>이전 문서에서 봤던 간단한 fetch() 예제를 살펴봅시다. :</p>
+
+<pre class="brush: js notranslate">fetch('coffee.jpg')
+.then(response =&gt; response.blob())
+.then(myBlob =&gt; {
+ let objectURL = URL.createObjectURL(myBlob);
+ let image = document.createElement('img');
+ image.src = objectURL;
+ document.body.appendChild(image);
+})
+.catch(e =&gt; {
+ console.log('There has been a problem with your fetch operation: ' + e.message);
+});</pre>
+
+<p>지금 시점에서 우리는 Promise가 어떻게 작동하는지 잘 이해하고 있습니다. 그렇다면 지금부터 이 예제를 async/await 를 사용하여 더 간단하게 만들어봅시다. :</p>
+
+<pre class="brush: js notranslate">async function myFetch() {
+ let response = await fetch('coffee.jpg');
+ let myBlob = await response.blob();
+
+ let objectURL = URL.createObjectURL(myBlob);
+ let image = document.createElement('img');
+ image.src = objectURL;
+ document.body.appendChild(image);
+}
+
+myFetch()
+.catch(e =&gt; {
+ console.log('There has been a problem with your fetch operation: ' + e.message);
+});</pre>
+
+<p>바꾸고 나니 더 이해하기 쉬워졌습니다. — 더 이상의 <code>.then()</code> 블럭은 찾아 볼 수 없습니다.</p>
+
+<p><code>async</code> 키워드가 함수를 Promise로 바꾸었기, 이제 promise 와 await의 하이브리드 접근방식을 사용하기 위해 코드를 리팩토링 할 수 있으며, 두 번째 <code>.then()</code>블럭을 함수 내부의 블럭으로 가져와 더 유연하게 만들 수 있습니다.</p>
+
+<pre class="brush: js notranslate">async function myFetch() {
+ let response = await fetch('coffee.jpg');
+ return await response.blob();
+}
+
+myFetch().then((blob) =&gt; {
+ let objectURL = URL.createObjectURL(blob);
+ let image = document.createElement('img');
+ image.src = objectURL;
+ document.body.appendChild(image);
+}).catch(e =&gt; console.log(e));</pre>
+
+<p>예제를 직접 만들어보거나, 여기서 결과를 확인할 수 있습니다. <a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/simple-fetch-async-await.html">live example</a> (see also the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/simple-fetch-async-await.html">source code</a>).</p>
+
+<h3 id="But_how_does_it_work">But how does it work?</h3>
+
+<p>함수 안에 코드를 작성했고, <code>function</code> 키워드 앞에 <code>async</code> 키워드를 썼다는 것을 알 수 있습니다. 꼭 이렇게 써야합니다!! 비동기 코드를 실행할 블럭을 정의하려면 비동기 함수를 생성해야 합니다. <code>await</code>는 <code>async function</code> 안에서만 쓸 수 있습니다.</p>
+
+<div class="blockIndicator note">
+<p><strong>Note:</strong> It's worth saying again, in a box with an eye-catching background color: <code>await</code> only works inside async functions.</p>
+</div>
+
+<p><code>myFetch()</code> 함수 내에 코드가 이전의 Promise버전과 매우 유사하지만, 다른점이 있습니다. <code>.then()</code>블럭을 사용하여 작업을 이어가는 대신 메서드 호출 전에 <code>await</code> 키워드를 사용하여 반환된 결과를 변수에 할당합니다. <code>await</code> 키워드는 JavaScript 런타임이 이 라인에서 비동기 코드를 일시 중지하여 비동기 함수 호출이 결과를 반환할 때 까지 기다리게 합니다. 그러나 외부의 다른 동기 코드는 실행될 수 있도록 합니다. 작업이 완료되면 코드는 계속 이어져서 실행됩니다. 예를들면 아래와 같습니다. :</p>
+
+<pre class="brush: js notranslate">let response = await fetch('coffee.jpg');</pre>
+
+<p>fullfilled된 <code>fetch()</code> Promise에서 반환된 응답은 해당 응답이 사용할 수 있게 되면 <code>response</code> 변수에 할당됩니다. 그리고 parser는 해당 응답이 발생할 때 까지 이 라인에서 일시 중지됩니다. response가 사용 가능하게 되면, parser 는 다음 라인으로 이동하게 되고 그 라인에서 <code><a href="/en-US/docs/Web/API/Blob">Blob</a></code> 을 생성하게 됩니다. 이라인도 Promise기반 비동기 메서드를 호출하므로, 여기서도<code>await</code> 을 사용합니다. 비동기 작업 결과가 반환되면, <code>myFetch()</code> 함수가 그 결과를 반환합니다.</p>
+
+<p><code>myFetch()</code> 함수를 호출하면, Promise를 반환하므로, 따라서 화면에 Blob을 표시해주는 <code>.then()</code> 코드 블럭 체이닝 할 수 있습니다.</p>
+
+<p>여기까지 왔으면 이 방법이 멋있다고 생각해야합니다! 왜냐하면 <code>.then()</code> 블럭이 줄어들고 대부분이 동기 코드처럼 보이기 때문에 정말 직관적입니다.</p>
+
+<h3 id="Adding_error_handling">Adding error handling</h3>
+
+<p>그리고 오류 처리를 하려면 몇 가지 옵션이 있습니다.</p>
+
+<p>동기식 코드에서 쓰는 <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/try...catch">try...catch</a></code> 구문을 <code>async</code>/<code>await</code>구조에서 사용할 수 있습니다. 이 예제는 위에서 설명한 첫 번째 코드를 수정한 것 입니다. :</p>
+
+<pre class="brush: js notranslate">async function myFetch() {
+ try {
+ let response = await fetch('coffee.jpg');
+ let myBlob = await response.blob();
+
+ let objectURL = URL.createObjectURL(myBlob);
+ let image = document.createElement('img');
+ image.src = objectURL;
+ document.body.appendChild(image);
+ } catch(e) {
+ console.log(e);
+ }
+}
+
+myFetch();</pre>
+
+<p><code>catch() {}</code> 블록은 <code>e</code> 라고 부르는 에러 오브젝트를 통과시킵니다. 이제 콘솔에 코드가 던져준 에러 메시지를 출력할 수 있습니다.</p>
+
+<p>아래 코드는 처음 예제를 리팩토링한 두 번째 버전의 코드 입니다. 이 하이브리드 접근법을 사용하는 코드에서 에러를 탐지하고 싶으면 <code>.catch()</code> 블럭을 <code>.then()</code> 호출의 마지막에 작성합니다. :</p>
+
+<pre class="brush: js notranslate">async function myFetch() {
+ let response = await fetch('coffee.jpg');
+ return await response.blob();
+}
+
+myFetch().then((blob) =&gt; {
+ let objectURL = URL.createObjectURL(blob);
+ let image = document.createElement('img');
+ image.src = objectURL;
+ document.body.appendChild(image);
+})
+.catch((e) =&gt;
+ console.log(e)
+);</pre>
+
+<p>이는 <code>.catch()</code> 블럭이 async 함수 호출과 Promise 체인 모두에서 발생하는 오류를 잡을 수 있기 때문입니다. 여기서 <code>try</code>/<code>catch</code> 블럭을 사용했더라도, <code>myFetch()</code> 에서 발생한 unhandled에러를 잡아낼 수 있습니다.</p>
+
+<p>위의 예제 모두를 GitHub에서 찾아볼 수 있습니다. :</p>
+
+<ul>
+ <li><a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/simple-fetch-async-await-try-catch.html">simple-fetch-async-await-try-catch.html</a> (see <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/simple-fetch-async-await-try-catch.html">source code</a>)</li>
+ <li><a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/simple-fetch-async-await-promise-catch.html">simple-fetch-async-await-promise-catch.html</a> (see <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/simple-fetch-async-await-promise-catch.html">source code</a>)</li>
+</ul>
+
+<h2 id="Awaiting_a_Promise.all">Awaiting a Promise.all()</h2>
+
+<p>async/await는 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">promises</a>의 상위에 만들어져 있기 때문에 Promise의 모든 기능을 사용할 수 있습니다. <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all">Promise.all()</a></code> 을 포함해서 말이죠 — 아래 보이는 코드처럼 <code>Promise.all()</code> 앞에 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">async</span></font>키워드를 사용하여 동기식 코드처럼 작성할 수 있습니다. 이전 문서를 확인해봅시다. <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/promise-all.html">an example we saw in our previous article</a>. 새로운 버전과 비교하기 위해 탭을 분리 해보세요.</p>
+
+<p>Aasync/await 스타일로 변경한 코드는 아래와 같습니다. (see <a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/promise-all-async-await.html">live demo</a> and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/promise-all-async-await.html">source code</a>) :</p>
+
+<pre class="brush: js notranslate">async function fetchAndDecode(url, type) {
+ let response = await fetch(url);
+
+ let content;
+
+ if(type === 'blob') {
+ content = await response.blob();
+ } else if(type === 'text') {
+ content = await response.text();
+ }
+
+ return content;
+}
+
+async function displayContent() {
+ let coffee = fetchAndDecode('coffee.jpg', 'blob');
+ let tea = fetchAndDecode('tea.jpg', 'blob');
+ let description = fetchAndDecode('description.txt', 'text');
+
+ let values = await Promise.all([coffee, tea, description]);
+
+ let objectURL1 = URL.createObjectURL(values[0]);
+ let objectURL2 = URL.createObjectURL(values[1]);
+ let descText = values[2];
+
+ let image1 = document.createElement('img');
+ let image2 = document.createElement('img');
+ image1.src = objectURL1;
+ image2.src = objectURL2;
+ document.body.appendChild(image1);
+ document.body.appendChild(image2);
+
+ let para = document.createElement('p');
+ para.textContent = descText;
+ document.body.appendChild(para);
+}
+
+displayContent()
+.catch((e) =&gt;
+  console.log(e)
+);</pre>
+
+<p>몇 가지 사항을 조금 수정했을 뿐인데 <code>fetchAndDecode()</code>함수를 쉽게 비동기 함수로 변환했습니다. <code>Promise.all()</code> 라인을 살펴보세요:</p>
+
+<pre class="brush: js notranslate">let values = await Promise.all([coffee, tea, description]);</pre>
+
+<p>여기에 <code>await</code> 을 사용하여 세 가지 Promise의 결과가 반환되었을 때 <code>values</code> 배열에 담을 수 있습니다. 그리고 마치 동기화 코드처럼 보이죠. 우리가 작업한건 <code>displayContent()</code>에 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">async</span></font>키워드를 추가하고, 모든 코드를<code>.then()</code> 블럭 바깥으로 빼냈습니다. 또한 아주 적은양의 코드 수정도 했죠. 이렇게 하니 더 단순하고, 유용하고 읽기 쉬운 프로그램이 되었습니다.</p>
+
+<p>마지막으로 에러를 다루기 위해 <code>.catch()</code> 블럭을 <code>displayContent()</code> 함수를 호출하는 곳에 추가했습니다. 이렇게 하면 두 함수에서 발생하는 에러를 처리할 수 있습니다.</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: It is also possible to use a sync <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/try...catch#The_finally_clause">finally</a></code> block within an async function, in place of a <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally">.finally()</a></code> async block, to show a final report on how the operation went — you can see this in action in our <a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/promise-finally-async-await.html">live example</a> (see also the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/promise-finally-async-await.html">source code</a>).</p>
+</div>
+
+<h2 id="The_downsides_of_asyncawait">The downsides of async/await</h2>
+
+<p>앞서 봤듯이 async/await 은매우 유용하지만 고려해야 할 몇 가지 단점이 있습니다.</p>
+
+<p>Async/await 는 우리의 코드를 마치 동기식 코드처럼 보이게 합니다. 그리고 어떤 면에서는 정말로 동기적으로 행동합니다. 함수 블럭에 여러 개의 <code>await</code> 키워드를 사용하면 Promise가 fulfilled되기 전 까지 다음 <code>await</code> 을 차단합니다. 그 동안 다른 태스크는 계속 실행이 되지만 정의한 함수 내에서는 동기적으로 작동할 것 입니다.</p>
+
+<p>이 말은 우리가 작성한 코드가 바로 이어지는 수 많은 Promise에 의해 느려질 수 있다는 것을 의미합니다. 각 <code>await</code> 는 이전의 작업이 끝날 때 까지 기다립니다(Promise 체이닝과 혼동하지 마세요). 그런데 우리가 원하는건 기다리는게 아니고 일제히 실행되는 것 입니다.</p>
+
+<p>이 문제를 완화할 수 있는 패턴이 있습니다. — 모든 <code>Promise</code> 오브젝트를 변수에 저장하여 미리 실행되게 하고 변수가 사용 가능할 때 꺼내서 쓰는 것 입니다. 어떻게 작동하는지 한번 살펴봅시다.</p>
+
+<p>두 가지 예시를 보여주겠습니다. — 느린 비동기 작업 <a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/slow-async-await.html">slow-async-await.html</a> (see <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/slow-async-await.html">source code</a>) 그리고 빠른 비동기 작업 <a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/fast-async-await.html">fast-async-await.html</a> (see <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/fast-async-await.html">source code</a>)입니다. 두 예제에서  마치 비동기 작업인 것 처럼 보이기 위해 <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout">setTimeout()</a></code> 을 사용했습니다. :</p>
+
+<pre class="brush: js notranslate">function timeoutPromise(interval) {
+ return new Promise((resolve, reject) =&gt; {
+ setTimeout(function(){
+ resolve("done");
+ }, interval);
+ });
+};</pre>
+
+<p>그리고 세 가지 <code>timeoutPromise()</code> 함수를 호출하는 <code>timeTest()</code>함수를 만들었습니다.</p>
+
+<pre class="brush: js notranslate">async function timeTest() {
+ ...
+}</pre>
+
+<p>그리고 두 개 예제 모두 시작 시간을 기록하고, <code>timeTest()</code> Promise가 fulfilled된 시간을 저장하여 두 시간의 차를 계산해 작업이 얼마나 걸렸는지 사용자에게 보여줍니다. :</p>
+
+<pre class="brush: js notranslate">let startTime = Date.now();
+timeTest().then(() =&gt; {
+ let finishTime = Date.now();
+ let timeTaken = finishTime - startTime;
+ alert("Time taken in milliseconds: " + timeTaken);
+})</pre>
+
+<p><code>timeTest()</code> 함수만 두 예제에서 차이가 있습니다.</p>
+
+<p><code>slow-async-await.html</code> 예제이서, <code>timeTest()</code> 함수는 아래와 같이 생겼습니다. :</p>
+
+<pre class="brush: js notranslate">async function timeTest() {
+ await timeoutPromise(3000);
+ await timeoutPromise(3000);
+ await timeoutPromise(3000);
+}</pre>
+
+<p>아주 간단하게 <code>timeoutPromise()</code> 함수를 직접 호출했습니다. 각 작업은 3초씩 걸립니다. 그리고 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">await</span></font> 키워드를 사용했기 때문에 이전 await 작업이 끝나야 다음으로 진행됩니다. — 첫 번째 예제를 실행하면, alert 박스에서 약 9초(9000밀리초)가 걸렸음을 확인할 수 있습니다.</p>
+
+<p>다음으로 <code>fast-async-await.html</code> 예제이서, <code>timeTest()</code> 은 아래와 같이 생겼습니다. :</p>
+
+<pre class="brush: js notranslate">async function timeTest() {
+ const timeoutPromise1 = timeoutPromise(3000);
+ const timeoutPromise2 = timeoutPromise(3000);
+ const timeoutPromise3 = timeoutPromise(3000);
+
+ await timeoutPromise1;
+ await timeoutPromise2;
+ await timeoutPromise3;
+}</pre>
+
+<p>여기선 세 가지 <code>Promise</code> 오브젝트를 변수에 저장하여 동시에 작업을 시작하도록 했습니다.</p>
+
+<p>그리고 그 변수에 await을 사용하여 결과를 호출합니다. — 작업이 거의 동시에 시작됐기 때문에, Promise도 거의 동시에 fulfilled될 것 입니다. 두 번째 예제를 실행하면 거의 3초(3000밀리초) 만에 작업이 끝났음을 확인할 수 있습니다.</p>
+
+<p>코드를 주의깊게 테스트 하고, 성능이 떨어지기 시작하면 위의 상황을 의심해봐야 합니다.</p>
+
+<p>다른 아주 사소한 단점은 비동기로 실행될 Promise가 있다면 async함수 안에 항상 await을 써야한다는 것 입니다.</p>
+
+<h2 id="Asyncawait_class_methods">Async/await class methods</h2>
+
+<p>마지막으로 보여줄 내용은 <code>async</code> 키워드를 class/object의 메서드에 사용하여 Promise를 반환하게 만들 수 있다는 것 입니다. 그리고 <code>await</code> 를 그 안에 넣을 수도 있습니다. 다음 문서를 살펴보세요 &gt; <a href="/en-US/docs/Learn/JavaScript/Objects/Inheritance#ECMAScript_2015_Classes">ES class code we saw in our object-oriented JavaScript article</a>, 그리고 보이는 코드를<code>async</code> 메서드로 수정한 아래의 내용과 비교 해보세요 :</p>
+
+<pre class="brush: js notranslate">class Person {
+ constructor(first, last, age, gender, interests) {
+ this.name = {
+ first,
+ last
+ };
+ this.age = age;
+ this.gender = gender;
+ this.interests = interests;
+ }
+
+ async greeting() {
+ return await Promise.resolve(`Hi! I'm ${this.name.first}`);
+ };
+
+ farewell() {
+ console.log(`${this.name.first} has left the building. Bye for now!`);
+ };
+}
+
+let han = new Person('Han', 'Solo', 25, 'male', ['Smuggling']);</pre>
+
+<p>이제 클래스의 첫 번째 메서드를 아래와 같이 사용할 수 있습니다. :</p>
+
+<pre class="brush: js notranslate">han.greeting().then(console.log);</pre>
+
+<h2 id="Browser_support">Browser support</h2>
+
+<p>One consideration when deciding whether to use async/await is support for older browsers. They are available in modern versions of most browsers, the same as promises; the main support problems come with Internet Explorer and Opera Mini.</p>
+
+<p>If you want to use async/await but are concerned about older browser support, you could consider using the <a href="https://babeljs.io/">BabelJS</a> library — this allows you to write your applications using the latest JavaScript and let Babel figure out what changes if any are needed for your user’s browsers. On encountering a browser that does not support async/await, Babel's polyfill can automatically provide fallbacks that work in older browsers.</p>
+
+<h2 id="Conclusion">Conclusion</h2>
+
+<p>And there you have it — async/await provide a nice, simplified way to write async code that is simpler to read and maintain. Even with browser support being more limited than other async code mechanisms at the time of writing, it is well worth learning and considering for use, both for now and in the future.</p>
+
+<p>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Promises", "Learn/JavaScript/Asynchronous/Choosing_the_right_approach", "Learn/JavaScript/Asynchronous")}}</p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">General asynchronous programming concepts</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Introducing asynchronous JavaScript</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">Cooperative asynchronous JavaScript: Timeouts and intervals</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Graceful asynchronous programming with Promises</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">Making asynchronous programming easier with async and await</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">Choosing the right approach</a></li>
+</ul>
diff --git a/files/ko/learn/javascript/asynchronous/concepts/index.html b/files/ko/learn/javascript/asynchronous/concepts/index.html
new file mode 100644
index 0000000000..443487fefb
--- /dev/null
+++ b/files/ko/learn/javascript/asynchronous/concepts/index.html
@@ -0,0 +1,159 @@
+---
+title: 일반적인 비동기 프로그래밍 개념
+slug: Learn/JavaScript/Asynchronous/Concepts
+tags:
+ - 비동기
+ - 비동기 프로그래밍
+ - 자바스크립트
+translation_of: Learn/JavaScript/Asynchronous/Concepts
+---
+<div>{{LearnSidebar}}{{NextMenu("Learn/JavaScript/Asynchronous/Introducing", "Learn/JavaScript/Asynchronous")}}</div>
+
+<p>이 문서에서는 비동기적 프로그래밍과 관련된 몇개의 개념들을 살펴볼 것입니다. 그리고 이것들이 웹브라우저와 자바스크립트에서 어떻게 보이는지도 살펴볼 것입니다. 이 모듈의 다른 문서들을 공부하기 전에, 이 문서에 나와있는 개념들을 먼저 학습하십시오.</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">선행 조건:</th>
+ <td>기초적인 컴퓨터 언어 능력,  Javascript에 대한 기초적인 이해가 필요합니다. </td>
+ </tr>
+ <tr>
+ <th scope="row">학습 목적: </th>
+ <td>비동기적 프로그래밍이 작동하는 기초적인 원리에 대해 이해하는 것입니다. 그리고 이 개념이 어떻게 웹브라우저와 자바스크립트에서 압도적인 지위를 차지하기 되었는지 알아봅니다. </td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="비동기적Asynchronous_이란">'비동기적'(Asynchronous) 이란?</h2>
+
+<p>일반적으로, 프로그램의 코드는 순차적으로 진행됩니다. 한번에 한가지 사건만 발생하면서 말입니다. 만약 어떤 함수의 결과가 다른 함수에 영향을 받는다면, 그 함수는 다른 함수가 끝나고 값을 산출할 때까지 기다려야 합니다. 그리고 그 과정이 끝날 때 까지, 유저의 입장에서 보자면,  전체 프로그램이 모두 멈춘 것처럼 보입니다. </p>
+
+<p>예를들면, 맥 유저라면 종종 회전하는 무지개색 커서(비치볼)를 본 적이 있을 것입니다. 이 커서는 오퍼레이팅 시스템이 이렇게 말하고 있는 것입니다. "당신이 지금 사용하고 있는 시스템은 지금 멈춰서서 뭔가가 끝나기를 기다려야만 합니다. 그리고 이 과정은 당신이 지금 무슨 일이 일어나고있는지 궁금해 할 만큼 오래 걸리고 있습니다."</p>
+
+<p><img alt="Multi-colored macOS beachball busy spinner" src="https://mdn.mozillademos.org/files/16577/beachball.jpg" style="display: block; float: left; height: 256px; margin: 0px 30px 0px 0px; width: 250px;"></p>
+
+<p>이것은 당황스러운 경험이며, 특히 요즘과 같이 컴퓨터가 여러개 프로세서를 돌리는 시대에는 컴퓨터 성능을 효율적으로 쓰지 못하는 처사입니다. 당신이 다른 코어 프로세서에 다른 작업들을 움직이게 하고 작업이 완료되면 알려줄 수 있을 때, 무언가를 기다리는 것은 의미가 없습니다 .그 동안 다른 작업을 수행할 수 있고, 이것이 비동기 프로그래밍의 기본입니다. 이러한 작업을 비동기적으로 실행할 수 있는 API를 제공하는 것은 당신이 사용하고 있는 프로그래밍 환경(웹 개발의 경우 웹브라우저) 에 달려 있습니다.</p>
+
+<h2 id="Blocking_code">Blocking code</h2>
+
+<p>비동기 기법은 특히 웹 프로그래밍에 매우 유용합니다. 웹 앱이 브라우저에서 특정 코드를 실행하느라 브라우저에게 제어권을 돌려주지 않으면 브라우저는 마치 정지된 것처럼 보일 수 있습니다. 이러한 현상을 <strong>blocking </strong>이라고 부릅니다. 자세히 정의하자면, 사용자의 입력을 처리하느라 웹 앱이 프로세서에 대한 제어권을 브라우저에게 반환하지 않는 현상 입니다..</p>
+
+<p>Blocking의 몇 가지 예를 살펴보겠습니다.</p>
+
+<p>여기 <a href="https://github.com/mdn/learning-area/tree/master/javascript/asynchronous/introducing">simple-sync.html</a> 예시가 있습니다. (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/simple-sync.html">see it running live</a>), 하나의 버튼에 클릭 이벤트리스너를 지정하여 시간이 오래 걸리는 처리를 하도록하였습니다. (날짜를 천만번 계산하고 마지막에 콘솔에 날짜를 출력합니다.) 그리고 처리가 끝나면 페이지에 간단한 문장을 한 줄 출력합니다. :</p>
+
+<pre class="brush: js notranslate">const btn = document.querySelector('button');
+btn.addEventListener('click', () =&gt; {
+ let myDate;
+ for(let i = 0; i &lt; 10000000; i++) {
+ let date = new Date();
+ myDate = date
+ }
+
+ console.log(myDate);
+
+ let pElem = document.createElement('p');
+ pElem.textContent = 'This is a newly-added paragraph.';
+ document.body.appendChild(pElem);
+});</pre>
+
+<p>이 예제를 실행할 때 JavaScript 콘솔을 열고 버튼을 클릭하면, 콘솔에 메시지가 출력되기 전 까지 페이지에 문장이 나타나지 않는다는 것을 알 수 있습니다. 코드는 위에서 아래로 순차적으로 실행되며, 아래쪽 코드는 위쪽 코드의 처리가 끝날 때 까지 실행되지 않습니다.</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: 앞의 예제는 매우 비현실적입니다. 실제 웹 앱에서 날짜를 천만번 계산할 일은 없습니다. 실제로 보여주기 위해 극단적인 예시를 들었을 뿐입니다..</p>
+</div>
+
+<p>두 번째 예제를 살펴보겠습니다. <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/simple-sync-ui-blocking.html">simple-sync-ui-blocking.html</a> (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/simple-sync-ui-blocking.html">see it live</a>),  페이지에 UI가 모두 표시되기 전 까지 사용자의 입력을 막는 좀 더 현실적인 예시입니다. 이번 예시에는 두 가지 버튼을 사용합니다. :</p>
+
+<ul>
+ <li>"Fill canvas" 버튼을 클릭하면 {{htmlelement("canvas")}} 태그에 100만개의 파란색 원을 채웁니다. (실행하면 원이 너무 많아서 원이 아니라 배경이 그냥 파란색으로 채워집니다.)</li>
+ <li>"Click me for alert" 버튼은 사용자에게 메시지를 출력합니다.</li>
+</ul>
+
+<pre class="brush: js notranslate">function expensiveOperation() {
+ for(let i = 0; i &lt; 1000000; i++) {
+ ctx.fillStyle = 'rgba(0,0,255, 0.2)';
+ ctx.beginPath();
+ ctx.arc(random(0, canvas.width), random(0, canvas.height), 10, degToRad(0), degToRad(360), false);
+ ctx.fill()
+ }
+}
+
+fillBtn.addEventListener('click', expensiveOperation);
+
+alertBtn.addEventListener('click', () =&gt;
+ alert('You clicked me!')
+);</pre>
+
+<p>첫 번째 버튼을 클릭한 후 두 번째 버튼을 바로 클릭하면 경고 박스가 나타나지 않는 것을 확인할 수 있습니다. 첫 번째 버튼은 이벤트가 끝나기 전 까지 다음 작동을 막아버립니다.</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: OK, in our case, it is ugly and we are faking the blocking effect, but this is a common problem that developers of real apps fight to mitigate all the time.</p>
+</div>
+
+<p>왜 이런 현상이 발생할까요? 답은 자바스크립트는 기본적으로 <strong>single threaded</strong>이기 때문입니다. 이 시점에서 <strong>threads</strong>의 개념을 소개할 필요가 있겠군요</p>
+
+<h2 id="Threads">Threads</h2>
+
+<p><strong>Thread</strong> 는 기본적으로 프로그램이 작업을 완료하는데 사용할 수 있는 단일 프로세스 입니다. 각 스레드는 한 번에 하나의 작업만 수행할 수 있습니다. :</p>
+
+<pre class="notranslate">Task A --&gt; Task B --&gt; Task C</pre>
+
+<p>위의 예시처럼 각 작업은 순차적으로 실행되며, 다음 작업을 시작하려면 앞의 작업이 완료되어야 합니다.</p>
+
+<p>앞서 말했듯이, 많은 컴퓨터들이 현재 여러 개의 CPU코어를 가지고 있기 때문에, 한 번에 여러가지 일을 수행할 수 있습니다. Multiple thread를 지원하는 프로그래밍 언어는 멀티코어 컴퓨터의 CPU를 사용하여 여러 작업을 동시에 처리할 수 있습니다. :</p>
+
+<pre class="notranslate">Thread 1: Task A --&gt; Task B
+Thread 2: Task C --&gt; Task D</pre>
+
+<h3 id="JavaScript_is_single_threaded">JavaScript is single threaded</h3>
+
+<p>자바스크립트는 전통적으로 싱글 thread입니다. 컴퓨터가 여러 개의 CPU를 가지고 있어도 <strong>main thread</strong>라 불리는 단일 thread에서만 작업을 실행할 수 있습니다. 위의 예시는 아래처럼 실행됩니다. :</p>
+
+<pre class="notranslate">Main thread: Render circles to canvas --&gt; Display alert()</pre>
+
+<p>JavaScript는 이러한 문제를 해결하기 위해 몇 가지 툴을 도입했습니다. <a href="https://wiki.developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API">Web workers</a>는 여러 개의 JavaScript 청크를 동시에 실행할 수 있도록 worker라고 불리는 별도의 스레드로 보낼 수 있습니다. 따라서 시간이 오래 걸리는 처리는 woker를 사용해 처리하면 blocking 발생을 막을 수 있습니다..</p>
+
+<pre class="notranslate"> Main thread: Task A --&gt; Task C
+Worker thread: Expensive task B</pre>
+
+<p>위의 내용을 잘 기억하시고 다음 예제를 살펴보세요. <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/simple-sync-worker.html">simple-sync-worker.html</a> (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/simple-sync-worker.html">see it running live</a>), JavaScript 콘솔을 함께 열어주세요. 이전 예시는 날짜를 천만 번 계산하고 페이지에 문장을 출력했지만, 이번엔 천만번 계산 전 문장을 페이지에 출력해줍니다. 더이상 첫 번째 작업이 두 번째 작업을 차단하지 않습니다.</p>
+
+<h2 id="Asynchronous_code">Asynchronous code</h2>
+
+<p>Web worker는 꽤 유용하지만 이들도 한계가 있습니다. 주요한 내용은 Web worker는 {{Glossary("DOM")}} 에 접근할 수 없습니다. — UI를 업데이트하도록 worker에게 어떠한 지시도 직접 할 수 없습니다. 두 번째 예시에서 worker는 100만개의 파란색 원을 만들 수 없습니다. 단순히 숫자만 계산합니다.</p>
+
+<p>두 번째 문제는 worker에서 실행되는 코드는 차단되지 않지만 동기적으로 실행된다는 것 입니다. 이러한 문제는 함수를 사용할 때 발생합니다. 어떤 함수가 일의 처리를 위해 이전의 여러 프로세스의 결과를 return 받아야 할 경우 입니다. 동기적으로 실행되면 함수 실행에 필요한 매개변수를 받아올 수 없는 경우가 생기므로 함수는 사용자가 원하는 기능을 제대로 실행할 수 없습니다.</p>
+
+<pre class="notranslate">Main thread: Task A --&gt; Task B</pre>
+
+<p>이 예시에서 Task A는 서버로부터 이미지를 가져오고 Task B는 그 이미지에 필터를 적용하는 것과 같은 작업을 수행한다고 가정합니다. Task A를 실행하고 결과를 반환할 시간도 없이 Task B를 실행해버리면 에러가 발생할 것 입니다. 왜냐햐면 Task A에서 이미지를 완전히 가져온 상태가 아니기 때문이죠.</p>
+
+<pre class="notranslate"> Main thread: Task A --&gt; Task B --&gt; |Task D|
+Worker thread: Task C -----------&gt; | |</pre>
+
+<p>이번 예시에선 Task D가 Task B와 Task C의 결과를 모두 사용한다고 가정합니다. Task B와 Task C가 동시에 아주 빠르게 결과를 반환하면 매우 이상적이겠지만, 현실은 그렇지 않습니다. Task D가 사용될 때 Task B, Task C 둘 중 어느 값이라도 입력이 되지 않을경우 에러가 발생합니다.</p>
+
+<p>이러한 문제를 해결하기 위해 브라우저를 통해 특정 작업을 비동기적으로 실행할 수 있습니다. 바로 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a> 를 사용하는것 입니다. 아래 예시처럼 Task A가 서버에서 이미지를 가져오는 동안 Task B를 기다리게 할 수 있습니다. :</p>
+
+<pre class="notranslate">Main thread: Task A Task B
+ Promise: |__async operation__|</pre>
+
+<p>위의 작업은 다른 곳에서 처리가 되므로, 비동기 작업이 진행되는 동안 main thread가 차단되지 않습니다.</p>
+
+<p>이번 문서에서 다룬 내용은 매우 중요한 내용입니다. 다음 문서에선 비동기 코드를 어떻게 쓸 수 있는지 살펴볼 계획이므로 끝까지 읽어주시면 좋겠습니다.</p>
+
+<h2 id="결론">결론</h2>
+
+<p>현대의 소프트웨어 설계는 프로그램이 한 번에 두 가지 이상의 일을 할 수 있도록 비동기 프로그래밍을 중심으로 돌아가고 있습니다. 보다 새롭고 강력한 API를 이용하면서, 비동기로 작업해야만 하는 사례가 많아질 것입니다. 예전에는 비동기 코드를 쓰기가 힘들었습니다. 여전히 아직 어렵지만, 훨씬 쉬워졌습니다. 이 모듈의 나머지 부분에서는 비동기 코드가 왜 중요한지, 위에서 설명한 일부 문제들을 방지하는 코드 설계 방법에 대해 자세히 알아봅시다.</p>
+
+<h2 id="이번_module_에서는..">이번 module 에서는..</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">일반적인 비동기 프로그래밍 개념</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">비동기 자바스크립트 소개</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">협동하는 비동기 자바스크립트: Timeouts and intervals</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Promises와 함께하는 우아한 비동기 프로그래밍</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">비동기 프로그래밍을 쉽게 만드는 방법: async and await</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">올바른 접근 방식 선택하기</a></li>
+</ul>
diff --git a/files/ko/learn/javascript/asynchronous/index.html b/files/ko/learn/javascript/asynchronous/index.html
new file mode 100644
index 0000000000..bcf2abdd45
--- /dev/null
+++ b/files/ko/learn/javascript/asynchronous/index.html
@@ -0,0 +1,59 @@
+---
+title: Asynchronous JavaScript
+slug: Learn/JavaScript/Asynchronous
+tags:
+ - Beginner
+ - CodingScripting
+ - Guide
+ - JavaScript
+ - Landing
+ - NeedsTranslation
+ - Promises
+ - TopicStub
+ - async
+ - asynchronous
+ - await
+ - callbacks
+ - requestAnimationFrame
+ - setInterval
+ - setTimeout
+translation_of: Learn/JavaScript/Asynchronous
+---
+<div>{{LearnSidebar}}</div>
+
+<p class="summary"><span class="seoSummary">In this module we take a look at {{Glossary("asynchronous")}} {{Glossary("JavaScript")}}, why it is important, and how it can be used to effectively handle potential blocking operations such as fetching resources from a server.</span></p>
+
+<h2 id="Prerequisites">Prerequisites</h2>
+
+<p>Asynchronous JavaScript is a fairly advanced topic, and you are advised to work through <a href="/en-US/docs/Learn/JavaScript/First_steps">JavaScript first steps</a> and <a href="/en-US/docs/Learn/JavaScript/Building_blocks">JavaScript building blocks</a> modules before attempting this.</p>
+
+<p>If you are not familiar with the concept of asynchronous programming, you should definitely start with the <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">General asynchronous programming concepts</a> article in this module. If you are, then you can probably skip to the <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Introducing asynchronous JavaScript</a> module.</p>
+
+<div class="note">
+<p><strong>Note</strong>: If you are working on a computer/tablet/other device where you don't have the ability to create your own files, you can try out (most of) the code examples in an online coding program such as <a href="http://jsbin.com/">JSBin</a> or <a href="https://thimble.mozilla.org/">Thimble</a>.</p>
+</div>
+
+<h2 id="Guides">Guides</h2>
+
+<dl>
+ <dt><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">General asynchronous programming concepts</a></dt>
+ <dd>
+ <p>In this article we'll run through a number of important concepts relating to asynchronous programming, and how this looks in web browsers and JavaScript. You should understand these concepts before working through the other articles in the module.</p>
+ </dd>
+ <dt><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Introducing asynchronous JavaScript</a></dt>
+ <dd>In this article we briefly recap the problems associated with sychronous JavaScript, and take a first look at some of the different asynchronous JavaScript techniques you'll encounter, showing how they can help us solve such problems.</dd>
+ <dt><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Loops_and_intervals">Cooperative asynchronous JavaScript: Timeouts and intervals</a></dt>
+ <dd>Here we look at the traditional methods JavaScript has available for running code asychronously after a set time period has elapsed, or at a regular interval (e.g. a set number of times per second), talk about what they are useful for, and look at their inherent issues.</dd>
+ <dt><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Handling async operations gracefully with Promises</a></dt>
+ <dd>Promises are a comparatively new feature of the JavaScript language that allow you to defer further actions until after the previous action has completed, or respond to its failure. This is really useful for setting up a sequence of operations to work correctly. This article shows you how promises work, where you'll see them in use in WebAPIs, and how to write your own.</dd>
+ <dt><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">Making asynchronous programming easier with async and await</a></dt>
+ <dd>Promises can be somewhat complex to set up and understand, and so modern browsers have implemented <code>async</code> functions and the <code>await</code> operator — the former allows standard functions to implicitly behave asynchronously with promises, whereas the latter can be used inside <code>async</code> functions to wait for promises before the function continues, making chaining of promises easier. This article explains <code>async</code>/<code>await</code>.</dd>
+ <dt><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">Choosing the right approach</a></dt>
+ <dd>To finish this module off, we'll consider the different coding techniques and features we've discussed throughout, looking at which ones you should use when, with recommendations and reminders of common pitfalls where appropriate.</dd>
+</dl>
+
+<h2 id="See_also">See also</h2>
+
+<ul>
+ <li><a href="https://eloquentjavascript.net/11_async.html">Asynchronous Programming</a> from the fantastic <a href="https://eloquentjavascript.net/">Eloquent JavaScript</a> online book by Marijn Haverbeke.</li>
+</ul>
diff --git a/files/ko/learn/javascript/asynchronous/introducing/index.html b/files/ko/learn/javascript/asynchronous/introducing/index.html
new file mode 100644
index 0000000000..a63eb66158
--- /dev/null
+++ b/files/ko/learn/javascript/asynchronous/introducing/index.html
@@ -0,0 +1,281 @@
+---
+title: Introducing asynchronous JavaScript
+slug: Learn/JavaScript/Asynchronous/Introducing
+translation_of: Learn/JavaScript/Asynchronous/Introducing
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Concepts", "Learn/JavaScript/Asynchronous/Timeouts_and_intervals", "Learn/JavaScript/Asynchronous")}}</div>
+
+<p class="summary">이 문서에선 JavaScript의 동기식 처리와 관련된 문제를 간략하게 요약하고, 앞으로 접하게 될 다른 비동기 기술들을 살펴보며, 어떻게 우리에게 도움이 될 수 있는지 살펴봅니다.</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">준비:</th>
+ <td>Basic computer literacy, a reasonable understanding of JavaScript fundamentals.</td>
+ </tr>
+ <tr>
+ <th scope="row">목표:</th>
+ <td>
+ <p>비동기 자바스크립트에 대해 더 알기 위해, 동기 스크립트와 어떤 부분이 다른지 그리고 사용 사례를 알 수 있다.</p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Synchronous_JavaScript">Synchronous JavaScript</h2>
+
+<p><strong>{{Glossary("asynchronous")}}</strong> JavaScript가 무엇인지 이해하려면, 우리는 <strong>{{Glossary("synchronous")}}</strong> JavaScript가 무엇인지 알아야 합니다. 이 문서에선 이전 문서에서 본 정보의 일부를 요약하겠습니다.</p>
+
+<p>이전의 학습 모듈에서 살펴본 많은 기능들은 동기식 입니다. — 약간의 코드를 실행하면, 브라우저가 할 수 있는 한 빠르게 결과를 보여줍니다. 다음 예제를 살펴볼까요 (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/basic-function.html">see it live here</a>, and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/basic-function.html">see the source</a>):</p>
+
+<pre class="brush: js notranslate">const btn = document.querySelector('button');
+btn.addEventListener('click', () =&gt; {
+ alert('You clicked me!');
+
+ let pElem = document.createElement('p');
+ pElem.textContent = 'This is a newly-added paragraph.';
+ document.body.appendChild(pElem);
+});
+</pre>
+
+<p>이 블럭에서 코드는 위에서 아래로 차례대로 실행됩니다. :</p>
+
+<ol>
+ <li>DOM에 미리 정의된 {{htmlelement("button")}} element 를 참조합니다.</li>
+ <li><code><a href="/en-US/docs/Web/API/Element/click_event">click</a></code> 이벤트 리스너를 만들어 버튼이 클릭됐을 때 아래 기능을 차례로 실행합니다. :
+ <ol>
+ <li><code><a href="/en-US/docs/Web/API/Window/alert">alert()</a></code> 메시지가 나타납니다.</li>
+ <li>메시지가 사라지면 {{htmlelement("p")}} element를 만듭니다.</li>
+ <li>그리고 text content를 만듭니다.</li>
+ <li>마지막으로 docuent body에 문장을 추가합니다.</li>
+ </ol>
+ </li>
+</ol>
+
+<p>각 작업이 처리되는 동안 렌더링은 일시 중지됩니다. <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">앞에서 말한 문서와 같이</a>, <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts#JavaScript_is_single_threaded">JavaScript 는 single threaded</a>이기 때문입니다. 한 번에 한 작업만, 하나의 main thread에서 처리될 수 있습니다. 그리고 다른 작업은 앞선 작업이 끝나야 수행됩니다.</p>
+
+<p>따라서 앞의 예제는 사용자가 OK 버튼을 누를 때까지 문장이 나타나지 않습니다. :</p>
+
+<div class="hidden">
+<pre class="brush: html notranslate">&lt;<span class="pl-ent">button</span>&gt;Click me&lt;/<span class="pl-ent">button</span>&gt;</pre>
+</div>
+
+<p>{{EmbedLiveSample('Synchronous_JavaScript', '100%', '70px')}}</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: 기억해두세요. <code><a href="/en-US/docs/Web/API/Window/alert">alert()</a></code> 는 동기 블럭을 설명하는데 아주 유용하지만, 실제 어플리케이션에서 사용하기엔 아주 끔찍합니다.</p>
+</div>
+
+<h2 id="Asynchronous_JavaScript">Asynchronous JavaScript</h2>
+
+<p>앞서 설명된 이유들 (e.g. related to blocking) 때문에 많은 웹 API기능은 현재 비동기 코드를 사용하여 실행되고 있습니다. 특히 외부 디바이스에서 어떤 종류의 리소스에 액세스 하거나 가져오는 기능들에 많이 사용합니다. 예를 들어 네트워크에서 파일을 가져오거나, 데이터베이스에 접속해 특정 데이터를 가져오는 일, 웹 캠에서 비디오 스트림에 엑세스 하거나, 디스플레이를 VR 헤드셋으로 브로드캐스팅 하는것 입니다.</p>
+
+<p>동기적 코드를 사용하여 작업을 처리하는데 왜 이렇게 어려울까요? 다음 예제를 살펴보겠습니다. 서버에서 이미지를 가져오면 네트워크 환경, 다운로드 속도 등의 영향을 받아 이미지를 즉시 확인할 수 없습니다. 이 말은 아래 코드가 (pseudocode) 실행되지 않는다는 의미 입니다. :</p>
+
+<pre class="brush: js notranslate">let response = fetch('myImage.png');
+let blob = response.blob();
+// display your image blob in the UI somehow</pre>
+
+<p>왜냐하면 앞서 설명했듯이 이미지를 다운로드 받는데 얼마나 걸릴지 모르기 때문입니다. 그래서 두 번째 줄을 실행하면 에러가 발생할 것 입니다. (이미지의 크키가 아주 작다면 에러가 발생하지 않을 수도 있습니다. 반대로 이미지의 크기가 크면 매번 발생할 것 입니다.) 왜냐하면 <code>response</code> 가 아직 제공되지 않았기 때문입니다. 따라서 개발자는 <code>response</code> 가 반환되기 전 까지 기다리게 처리를 해야합니다.</p>
+
+<p>JavaScript에서 볼 수 있는 비동기 스타일은 두 가지 유형이 있습니다, 예전 방식인 callbacks 그리고 새로운 방식인 promise-style 코드 입니다. 이제부터 차례대로 살펴보겠습니다.</p>
+
+<h2 id="Async_callbacks">Async callbacks</h2>
+
+<p>Async callbacks은 백그라운드에서 코드 실행을 시작할 함수를 호출할 때 인수로 지정된 함수입니다. 백그라운드 코드 실행이 끝나면 callback 함수를 호출하여 작업이 완료됐음을 알리거나, 다음 작업을 실행하게 할 수 있습니다. callbacks을 사용하는 것은 지금은 약간 구식이지만, 여전히 다른 곳에서 사용이 되고있음을 확인할 수 있습니다.</p>
+
+<p>Async callback 의 예시는 {{domxref("EventTarget.addEventListener", "addEventListener()")}} 'click' 옆의 두 번째 매개변수 입니다. :</p>
+
+<pre class="brush: js notranslate">btn.addEventListener('click', () =&gt; {
+ alert('You clicked me!');
+
+ let pElem = document.createElement('p');
+ pElem.textContent = 'This is a newly-added paragraph.';
+ document.body.appendChild(pElem);
+});</pre>
+
+<p>첫 번째 매개 변수는 이벤트 리스너 유형이며, 두 번째 매개 변수는 이벤트가 실행 될 때 호출되는 콜백 함수입니다.</p>
+
+<p>callback 함수를 다른 함수의 인수로 전달할 때, 함수의 참조를 인수로 전달할 뿐이지 즉시 실행되지 않고, 함수의 body에서 “called back”됩니다. 정의된 함수는 때가 되면 callback 함수를 실행하는 역할을 합니다.</p>
+
+<p><a href="/en-US/docs/Web/API/XMLHttpRequest"><code>XMLHttpRequest</code> API</a> (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/xhr-async-callback.html">run it live</a>, and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/xhr-async-callback.html">see the source</a>)를 불러오는 예제를 통해 callback 함수를 쉽게 사용해봅시다. :</p>
+
+<pre class="brush: js notranslate">function loadAsset(url, type, callback) {
+ let xhr = new XMLHttpRequest();
+ xhr.open('GET', url);
+ xhr.responseType = type;
+
+ xhr.onload = function() {
+ callback(xhr.response);
+ };
+
+ xhr.send();
+}
+
+function displayImage(blob) {
+ let objectURL = URL.createObjectURL(blob);
+
+ let image = document.createElement('img');
+ image.src = objectURL;
+ document.body.appendChild(image);
+}
+
+loadAsset('coffee.jpg', 'blob', displayImage);</pre>
+
+<p><code>displayImage()</code>함수는 Object URL로 전달되는 Blob을 전달받아, URL이 나탸내는 이미지를 만들어 <code>&lt;body&gt;</code>에 그립니다. 그러나, 우리는 <code>loadAsset()</code> 함수를 만들고 "url", "type" 그리고 "callback"을 매개변수로 받습니다. <code>XMLHttpRequest</code> (줄여서 "XHR") 를 사용하여 전달받은 URL에서 리소스를 가져온 다음 callback으로 응답을 전달하여 작업을 수행합니다. 이 경우 callback은 callback 함수로 넘어가기 전, 리소스 다운로드를 완료하기 위해 XHR 요청이 진행되는 동안 대기합니다. (<code><a href="/en-US/docs/Web/API/XMLHttpRequestEventTarget/onload">onload</a></code> 이벤트 핸들러 사용)</p>
+
+<p>Callbacks은 다재다능 합니다. 함수가 실행되는 순서, 함수간에 어떤 데이터가 전달되는지를 제어할 수 있습니다. 또한 상황에 따라 다른 함수로 데이터를 전달할 수 있습니다. 따라서 응답받은 데이터에 따라 (<code>processJSON()</code>, <code>displayText()</code>등) 어떤 작업을 수행할지 지정할 수 있습니다.</p>
+
+<p>모든 callback이 비동기인 것은 아니라는 것에 유의하세요 예를 들어 {{jsxref("Array.prototype.forEach()")}} 를 사용하여 배열의 항목을 탐색할 때가 있습니다. (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/foreach.html">see it live</a>, and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/foreach.html">the source</a>):</p>
+
+<pre class="brush: js notranslate">const gods = ['Apollo', 'Artemis', 'Ares', 'Zeus'];
+
+gods.forEach(function (eachName, index){
+ console.log(index + '. ' + eachName);
+});</pre>
+
+<p>이 예제에선 그리스 신들의 배열을 탐색하여 인덱스 넘버와 그 값을 콘솔에 출력합니다. <code>forEach()</code> 매개변수는 callback 함수이며, callback 함수는 배열 이름과 인덱스 총 두 개의 매개변수가 있습니다. 그러나, 여기선 비동기로 처리되지 않고 즉시 실행됩니다..</p>
+
+<h2 id="Promises">Promises</h2>
+
+<p>Promises 모던 Web APIs에서 보게 될 새로운 코드 스타일 입니다. 좋은 예는 <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch">fetch()</a></code> API 입니다. <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch">fetch()</a></code>는 {{domxref("XMLHttpRequest")}}보다 좀 더 현대적인 버전 입니다. 아래 <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Fetching data from the server</a> 예제에서 빠르게 살펴볼까요?  :</p>
+
+<pre class="brush: js notranslate">fetch('products.json').then(function(response) {
+  return response.json();
+}).then(function(json) {
+  products = json;
+  initialize();
+}).catch(function(err) {
+  console.log('Fetch problem: ' + err.message);
+});</pre>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: You can find the finished version on GitHub (<a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/can-store-xhr/can-script.js">see the source here</a>, and also <a href="https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store-xhr/">see it running live</a>).</p>
+</div>
+
+<p><code>fetch</code><code>()</code> 는 단일 매개변수만 전달받습니다. — 네트워크에서 가지고 오고 싶은 리소스의 URL — 그리고 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">promise</a>로 응답합니다. promise 는 비동기 작업이 성공 했는지 혹은 실패했는지를 나타내는 하나의 오브젝트 입니다. 즉 성공/실패 의 분기점이 되는 중간의 상태라고 표현할 수 있죠. 왜 promise라는 이름이 붙었는지 잠깐 살펴보자면.. "내가 할수 있는 한 빨리 너의 요청의 응답을 가지고 돌아간다고 약속(promise)할게" 라는 브라우저의 표현방식 이어서 그렇습니다.</p>
+
+<p>이 개념에 익숙해 지기 위해서는 연습이 필요합니다.; 마치 {{interwiki("wikipedia", "Schrödinger's cat")}}(슈뢰딩거의 고양이) 처럼 느껴질 수 있습니다. 위의 예제에서도 발생 가능한 결과 중 아직 아무것도 발생하지 않았기 때문에, 미래에 어떤 시점에서 <code>fetch()</code>작업이 끝났을때 어떤 작업을 수행 시키기 위해 두 가지 작업이 필요합니다. 예제에선 <code>fetch()</code> 마지막에 세 개의 코드 블럭이 더 있는데 이를 살펴보겠습니다. :</p>
+
+<ul>
+ <li>두 개의 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">then()</a></code> 블럭: 두 함수 모두 이전 작업이 성공했을때 수행할 작업을 나타내는 callback 함수 입니다. 그리고 각 callback함수는 인수로 이전 작업의 성공 결과를 전달받습니다. 따라서 성공했을때의 코드를 callback 함수 안에 작성하면 됩니다. 각 <code>.then()</code> 블럭은 서로 다른 promise를 반환합니다. 이 말은 <code>.then()</code> 을 여러개 사용하여 연쇄적으로 작업을 수행하게 할 수 있음을 말합니다. 따라서 여러 비동기 작업을 차례대로 수행할 수 있습니다.</li>
+ <li><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch">catch()</a></code> 블럭은 <code>.then()</code> 이 하나라도 실패하면 동작합니다. — 이는 동기 방식의 <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/try...catch">try...catch</a></code> 블럭과 유사합니다. error 오브젝트는 <code>catch()</code>블럭 안에서 사용할 수 있으며, 발생한 오류를 보고하는 용도로 사용할 수 있습니다. 그러나 <code>try...catch</code> 는 나중에 배울 <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">async/await</a>에서는 동작하지만, promise와 함께 동작할 수 없음을 알아두세요.</li>
+</ul>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: You'll learn a lot more about promises later on in the module, so don't worry if you don't understand them fully yet.</p>
+</div>
+
+<h3 id="The_event_queue">The event queue</h3>
+
+<p>promise와 같은 비동기 작업은 <strong>event queue</strong>에 들어갑니다. 그리고 main thread가 끝난 후 실행되어 후속 JavaScript 코드가 차단되는것을 방지합니다. queued 작업은 가능한 빨리 완료되어 JavaScript 환경으로 결과를 반환해줍니다.</p>
+
+<h3 id="Promises_vs_callbacks">Promises vs callbacks</h3>
+
+<p>Promises 는 old-style callbacks과 유사한 점이 있습니다. 기본적으로 callback을 함수로 전달하는 것이 아닌 callback함수를 장착하고 있는 returned된 오브젝트 입니다.</p>
+
+<p>그러나 Promise는 비동기 작업을 처리함에 있어서 old-style callbacks 보다 더 많은 이점을 가지고 있습니다. :</p>
+
+<ul>
+ <li>여러 개의 연쇄 비동기 작업을 할 때 앞서 본 예제처럼 <code>.then()</code> 을 사용하여 결과값을 다음 작업으로 넘길 수 있습니다. callbacks으로 이를 사용하려면 더 어렵습니다. 또한 "파멸의 피라미드" (<a href="http://callbackhell.com/">callback hell</a>로 잘 알려진)을 종종 마주칠 수 있습니다.</li>
+ <li>Promise callbacks은 event queue에 배치되는 엄격한 순서로 호출됩니다.</li>
+ <li>에러 처리가 더 간결해집니다. — 모든 에러를 코드 블럭의 마지막 부분에 있는 단 한개의 <code>.catch()</code> 블럭으로 처리할 수 있습니다. 이 방법은 피라미드의 각 단계에서 에러를 핸들링하는 것 보다 더 간단합니다..</li>
+ <li>구식 callback은 써드파티 라이브러리에 전달될 때 함수가 어떻게 실행되어야 하는 방법을 상실하는 반면 Promise는 그렇지 않습니다.</li>
+</ul>
+
+<h2 id="The_nature_of_asynchronous_code">The nature of asynchronous code</h2>
+
+<p>코드 실행 순서를 완전히 알지 못할 때 발생하는 현상과 비동기 코드를 동기 코드처럼 취급하려고 하는 문제를 살펴보면서 비동기 코드의 특성을 더 살펴봅시다 아래 예제는 이전에 봤던 예제와 유사합니다. (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/async-sync.html">see it live</a>, and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/async-sync.html">the source</a>). 한가지 다른 점은 코드가 실행순서를 보여주기 위해 {{domxref("console.log()")}} 를 추가했습니다.</p>
+
+<pre class="brush: js notranslate">console.log ('Starting');
+let image;
+
+fetch('coffee.jpg').then((response) =&gt; {
+ console.log('It worked :)')
+ return response.blob();
+}).then((myBlob) =&gt; {
+ let objectURL = URL.createObjectURL(myBlob);
+ image = document.createElement('img');
+ image.src = objectURL;
+ document.body.appendChild(image);
+}).catch((error) =&gt; {
+ console.log('There has been a problem with your fetch operation: ' + error.message);
+});
+
+console.log ('All done!');</pre>
+
+<p>브라우저는 코드를 실행하기 시작할 것이고, 맨 처음 나타난 (<code>Starting</code>) 글씨가 써진 <code>console.log()</code> 후 <code>image</code> 변수를 만들 것 입니다.</p>
+
+<p>다음으로 <code>fetch()</code> block 으로 이동하여 코드를 실행하려고 할 것 입니다. <code>fetch()</code> 덕분에 blocking없이 비동기 적으로 코드가 실행되겠죠. 블럭 내에서 promise와 관련된 작업이 끝나면 다음 작업으로 이어질 것 입니다. 그리고 마지막으로 (<code>All done!</code>) 가 적혀있는 <code>console.log()</code> 에서 메시지를 출력할 것 입니다.</p>
+
+<p><code>fetch()</code> 블럭 작업이 작업을 완전히 끝내고 마지막 <code>.then()</code> 블럭에 도달해야 <code>console.log()</code> 의 (<code>It worked :)</code>) 메시지가 나타납니다. 그래서 메시지의 순서는 코드에 적혀있는 대로 차례대로 나타나는게 아니라 순서가 약간 바뀌어서 나타납니다 :</p>
+
+<ul>
+ <li>Starting</li>
+ <li>All done!</li>
+ <li>It worked :)</li>
+</ul>
+
+<p>이 예가 어렵다면 아래의 다른 예를 살펴보세요 :</p>
+
+<pre class="brush: js notranslate">console.log("registering click handler");
+
+button.addEventListener('click', () =&gt; {
+ console.log("get click");
+});
+
+console.log("all done");</pre>
+
+<p>이전 예제와 매우 유사한 예제 입니다. — 첫 번째와 세 번째<code>console.log()</code> 메시지는 콘솔창에 바로 출력됩니다. 그러나 두 번째 메시지는 누군가가 버튼을 클릭하기 전엔 콘솔에 표시되지 않죠. 위의 예제의 차이라면 두 번쩨 메시지가 어떻게 잠시 blocking이 되는지 입니다. 첫 예제는 Promise 체이닝 때문에 발생하지만 두 번째 메시지는 클릭 이벤트를 대기하느라고 발생합니다.</p>
+
+<p>less trivial 코드 예제에서 이러한 설정을 문제를 유발할 수 있습니다. — 비동기 코드 블럭에서 반환된 결과를 동기화 코드 블럭에 사용할 수 없습니다. 위의 에시에서 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">image</span></font> 변수가 그 예시 입니다. 브라우저가 동기화 코드 블럭을 처리하기 전에 비동기 코드 블럭 작업이 완료됨을 보장할 수 없습니다.</p>
+
+<p>어떤 의미인지 확인을 하려면 <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/async-sync.html">our example</a>을 컴퓨터에 복사한 후 마지막 <code>console.log()</code> 를 아래처럼 고쳐보세요:</p>
+
+<pre class="brush: js notranslate">console.log ('All done! ' + image.src + 'displayed.');</pre>
+
+<p>고치고 나면 콘솔창에서 아래와 같은 에러가 뜨는것을 확인할 수 있습니다. :</p>
+
+<pre class="notranslate"><span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body">TypeError: image is undefined; can't access its "src" property</span></span></span></pre>
+
+<p>브라우저가 마지막 <code>console.log()</code> 를 처리할 때, <code>fetch()</code> 블럭이 완료되지 않아 <code>image</code> 변수에 결과가 반환되지 않았기 때문입니다.</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: For security reasons, you can't <code>fetch()</code> files from your local filesystem (or run other such operations locally); to run the above example locally you'll have to run the example through a <a href="/en-US/docs/Learn/Common_questions/set_up_a_local_testing_server">local webserver</a>.</p>
+</div>
+
+<h2 id="Active_learning_make_it_all_async!">Active learning: make it all async!</h2>
+
+<p>위의 <code>fetch()</code> 예시에서 마지막<code>console.log()</code>도 순서대로 나타나도록 고칠 수 있습니다. 마지막 <code>console.log()</code> 도 비동기로 작동시키면 됩니다. 마지막 <code>.then()</code> 블럭의 마지막에 다시 작성하거나, 새로운 블럭을 만들면 콘솔에 순서대로 나타날 것 입니다. 지금 바로 고쳐보세요!</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: If you get stuck, you can <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/async-sync-fixed.html">find an answer here</a> (see it <a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/async-sync-fixed.html">running live</a> also). You can also find a lot more information on promises in our <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Graceful asynchronous programming with Promises</a> guide, later on in the module.</p>
+</div>
+
+<h2 id="Conclusion">Conclusion</h2>
+
+<p>In its most basic form, JavaScript is a synchronous, blocking, single-threaded language, in which only one operation can be in progress at a time. But web browsers define functions and APIs that allow us to register functions that should not be executed synchronously, and should instead be invoked asynchronously when some kind of event occurs (the passage of time, the user's interaction with the mouse, or the arrival of data over the network, for example). This means that you can let your code do several things at the same time without stopping or blocking your main thread.</p>
+
+<p>Whether we want to run code synchronously or asynchronously will depend on what we're trying to do.</p>
+
+<p>There are times when we want things to load and happen right away. For example when applying some user-defined styles to a webpage you'll want the styles to be applied as soon as possible.</p>
+
+<p>If we're running an operation that takes time however, like querying a database and using the results to populate templates, it is better to push this off the main thread and complete the task asynchronously. Over time, you'll learn when it makes more sense to choose an asynchronous technique over a synchronous one.</p>
+
+<ul>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Concepts", "Learn/JavaScript/Asynchronous/Timeouts_and_intervals", "Learn/JavaScript/Asynchronous")}}</p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">General asynchronous programming concepts</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Introducing asynchronous JavaScript</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">Cooperative asynchronous JavaScript: Timeouts and intervals</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Graceful asynchronous programming with Promises</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">Making asynchronous programming easier with async and await</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">Choosing the right approach</a></li>
+</ul>
diff --git a/files/ko/learn/javascript/asynchronous/promises/index.html b/files/ko/learn/javascript/asynchronous/promises/index.html
new file mode 100644
index 0000000000..bf7a5a0f04
--- /dev/null
+++ b/files/ko/learn/javascript/asynchronous/promises/index.html
@@ -0,0 +1,588 @@
+---
+title: Graceful asynchronous programming with Promises
+slug: Learn/JavaScript/Asynchronous/Promises
+translation_of: Learn/JavaScript/Asynchronous/Promises
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Timeouts_and_intervals", "Learn/JavaScript/Asynchronous/Async_await", "Learn/JavaScript/Asynchronous")}}</div>
+
+<p class="summary"><span class="seoSummary"><strong>Promises</strong> 는 이전 작업이 완료될 때 까지 다음 작업을 연기 시키거나, 작업실패를 대응할 수 있는 비교적 새로운 JavaScript 기능입니다.</span> Promise는 비동기 작업 순서가 정확하게 작동되게 도움을 줍니다. 이번 문서에선 Promise가 어떻게 동작하는지, 웹 API와 어떻게 사용할 수 있는지 그리고 직접 코드를 만들어 볼것 입니다. </p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Prerequisites:</th>
+ <td>Basic computer literacy, a reasonable understanding of JavaScript fundamentals.</td>
+ </tr>
+ <tr>
+ <th scope="row">Objective:</th>
+ <td>To understand promises and how to use them.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="What_are_promises">What are promises?</h2>
+
+<p>앞서서 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a> 를 미리 봤지만, 지금부턴 좀더 깊이있게 들여다 볼 차례 입니다..</p>
+
+<p>Promise는 어떤 작업의 중간상태를 나타내는 오브젝트 입니다. — 미래에 어떤 종류의 결과가 반환됨을 <em>promise</em> (약속) 해주는 오브젝트라고 보면 됩니다. Promise는 작업이 완료되어 결과를 반환해주는 정확한 시간을 보장해주지는 않지만, 사용할 수 있는 결과를 반환했을때 프로그래머의 의도대로 다음 코드를 진행 시키거나, 에러가 발생했을 때 그 에러를 우아하게/깔끔하게 처리할 수 있습니다.</p>
+
+<p>일반적으로 우리는 비동기 작업이 결과를 반환하는데 얼마의 시간이 걸리는지 보다는(<em>작업 시간이 매우 오래 걸리지 않는 한</em>) 그 결과를 사용할 수 있는지 여부에 더 관심이 있습니다.  물론 나머지 코드 블럭을 막지 않는다는 것에 있어서 매우 좋습니다.</p>
+
+<p>우리가 Promise로 가장 많이 할 작업중 하나는 Promise를 반환하는 웹API를 사용하는 것 입니다. 가상의 비디오 채팅 애플리케이션이 있다고 해봅시다. 애플리케이션에는 친구 목록이 있고 각 친구 목록 옆의 버튼을 클릭하면 해당 친구와 비디오 채팅을 시작합니다.</p>
+
+<p>그 버튼은 사용자 컴퓨터의 카메라와 마이크를 사용하기 위해 {{domxref("MediaDevices.getUserMedia", "getUserMedia()")}} 를 호출합니다. <code>getUserMedia()</code> 는 사용자가 이러한 장치를 사용할 수 있는 권한을 가지고 있는지 확인해야 하고, 어떤 마이크와 카메라를 사용할 것인지 (혹은 음성 통화인지, 아니면 다른 옵션들이 있는지)를 체크해야하기 때문에 모든 결정이 내려질 때 까지 다음 작업을 차단할 수 있습니다. 또한 카메라와 마이크가 작동하기 전 까지 다음 작업을 차단할수도 있습니다.</p>
+
+<p><code>getUserMedia()</code> 는 브라우저의 main thread에서 실행되므로 <code>getUserMedia()</code> 결과가 반환되기 전 까지 후행 작업이 모두 차단됩니다. 이러한 blocking은 우리가 바라는게 아닙니다. Promise가 없으면 이러한 결정이 내려지기 전 까지 브라우저의 모든 것을 사용할 수 없게됩니다. 따라서 사용자가 선택한 장치를 활성화하고 소스에서 선택된 스트림에 대해{{domxref("MediaStream")}} 직접 반환하는 대신 <code>getUserMedia()</code> 는 모든 장치가 사용 가능한 상태가 되면 {{domxref("MediaStream")}}이 포함된 {{jsxref("promise")}}를 반환합니다.</p>
+
+<p>비디오 채팅 애플리케이션의 코드는 아래처럼 작성할 수 있습입니다. :</p>
+
+<pre class="brush: js notranslate">function handleCallButton(evt) {
+ setStatusMessage("Calling...");
+ navigator.mediaDevices.getUserMedia({video: true, audio: true})
+ .then(chatStream =&gt; {
+ selfViewElem.srcObject = chatStream;
+ chatStream.getTracks().forEach(track =&gt; myPeerConnection.addTrack(track, chatStream));
+ setStatusMessage("Connected");
+ }).catch(err =&gt; {
+ setStatusMessage("Failed to connect");
+ });
+}
+</pre>
+
+<p>이 기능은 상태 메시지에 "Calling..."을 출력하는 <code>setStatusMessage()</code> 함수로 시작하며 통화가 시도되고 있음을 나타냅니다. 그런 다음 <code>getUserMedia()</code>을 호출하여 비디오와 오디오 트랙이 모두 있는 스트림 요청을 합니다. 그리고 스트림을 획득하면 카메라에서 나오는 스트림을 "self view,"로 표시하기 위해 video엘리먼트를 설정합니다. 그리고 각 스트림의 트랙을 가져가 다른 사용자와의 연결을 나타내는 <a href="/en-US/docs/Web/API/WebRTC_API">WebRTC</a> {{domxref("RTCPeerConnection")}}에 추가합니다. 그리고 마지막으로 상태 메시지를 "Connected"로 업데이트 합니다.</p>
+
+<p><code>getUserMedia()</code> 가 실패하면, <code>catch</code> 블럭이 실행되며, <code>setStatusMessage()</code> 를 사용하여 상태창에 오류 메시지를 표시합니다.</p>
+
+<p>여기서 중요한건 <code>getUserMedia()</code>는 카메라 스트림이 아직 확보되지 않았음에도 거의 즉시 반환을 해줬다는 것 입니다. <code>handleCallButton()</code> 함수가 자신을 호출한 코드로 결과를 이미 반환을 했더라도 <code>getUserMedia()</code>의 작업이 종료되면 프로그래머가 작성한 다음 핸들러를 호출할 것 입니다. 앱이 스트리밍을 했다고 가정하지 않는 한 계속 실행될 수 있습니다.</p>
+
+<div class="blockIndicator note">
+<p><strong>Note:</strong> You can learn more about this somewhat advanced topic, if you're interested, in the article <a href="/docs/Web/API/WebRTC_API/Signaling_and_video_calling">Signaling and video calling</a>. Code similar to this, but much more complete, is used in that example.</p>
+</div>
+
+<h2 id="The_trouble_with_callbacks">The trouble with callbacks</h2>
+
+<p>Promise가 왜 좋은지 이해하기 위해 구식 callbacks을 살펴보고 어떤게 문제인지 파악 해보겠습니다.</p>
+
+<p>피자를 주문한다고 생각해봅시다. 피자를 잘 주문하려면 몇 가지 단계를 진행해야 합니다. 토핑 위에 도우를 올리고 치즈를 뿌리는 등 각 단계가 뒤죽박죽 이거나 혹은 도우를 반죽하고 있는데 그 위에 토마토소스를 바르는 등 이전 작업이 끝나지 않고 다음 작업을 진행하는 것은 말이 안 됩니다.  :</p>
+
+<ol>
+ <li>먼저 원하는 토핑을 고릅니다. 결정 장애가 심할 경우 토핑을 고르는데 오래 걸릴 수 있습니다. 또한 마음을 바꿔 피자 대신 카레를 먹으려고 가게를 나올 수 있습니다.</li>
+ <li>그다음 피자를 주문합니다. 식당이 바빠서 피자가 나오는 데 오래 걸릴 수 있고, 마침 재료가 다 떨어졌으면 피자를 만들 수 없다고 할 것 입니다.</li>
+ <li>마지막으로 피자를 받아서 먹습니다. 그런데! 만약 지갑을 놓고 와서 돈을 내지 못한다면 피자를 먹지 못할 수 있습니다.</li>
+</ol>
+
+<p>구식 <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing#Callbacks">callbacks</a>을 사용하면 아래와 같은 모습의 코드가 나타날것 입니다. :</p>
+
+<pre class="brush: js notranslate">chooseToppings(function(toppings) {
+ placeOrder(toppings, function(order) {
+ collectOrder(order, function(pizza) {
+ eatPizza(pizza);
+ }, failureCallback);
+ }, failureCallback);
+}, failureCallback);</pre>
+
+<p>이런 코드는 읽기도 힘들 뿐 아니라 (종종 "콜백 지옥" 이라 불림), <code>failureCallback()</code> 을 여러 번 작성해야 하며 또한 다른 문제점도 가지고 있습니다.</p>
+
+<h3 id="Improvements_with_promises">Improvements with promises</h3>
+
+<p>위의 상황에서 Promise를 사용하면 읽기, 작성, 실행 모두 다 쉬워집니다. callback 대신 비동기 Promise를 사용하면 아래처럼 작성할 수 있습니다.  :</p>
+
+<pre class="brush: js notranslate">chooseToppings()
+.then(function(toppings) {
+ return placeOrder(toppings);
+})
+.then(function(order) {
+ return collectOrder(order);
+})
+.then(function(pizza) {
+ eatPizza(pizza);
+})
+.catch(failureCallback);</pre>
+
+<p>보기에 훨씬 더 좋군요! — 이렇게 작성하면 앞으로 어떤 일이 일어날지 쉽게 예측 가능합니다. 그리고 단 한개의 <code>.catch()</code> 을 사용하여 모든 에러를 처리합니다. 그리고 main thread를 차단하지 않습니다. (그래서 피자를 주문하고 기다리는 동안 하던 게임을 마저 할 수 있습니다.), 또한 각 함수가 실행되기 전 이전 작업이 끝날때까지 기다립니다. 이런식으로 여러 개의 비동기 작업을 연쇄적으로 처리할 수 있습니다. 왜냐햐면 각 <code>.then()</code> 블럭은 자신이 속한 블럭의 작업이 끝났을 때의 결과를 새로운 Promise 반환해주기 때문입니다. 어때요, 참 쉽죠?</p>
+
+<p>화살표 함수를 사용하면 코드를 조금 더 간단하게 고칠 수 있습니다. :</p>
+
+<pre class="brush: js notranslate">chooseToppings()
+.then(toppings =&gt;
+ placeOrder(toppings)
+)
+.then(order =&gt;
+ collectOrder(order)
+)
+.then(pizza =&gt;
+ eatPizza(pizza)
+)
+.catch(failureCallback);</pre>
+
+<p>혹은 아래처럼 표현할 수 있습니다. :</p>
+
+<pre class="brush: js notranslate">chooseToppings()
+.then(toppings =&gt; placeOrder(toppings))
+.then(order =&gt; collectOrder(order))
+.then(pizza =&gt; eatPizza(pizza))
+.catch(failureCallback);</pre>
+
+<p>화살표 함수의 <code>() =&gt; x</code> 표현은 <code>() =&gt; { return x; }</code>의 약식 표현이므로 잘 작동합니다.</p>
+
+<p>함수는 arguments를 직접 전달 하므로 함수처럼 표현하지 않고 아래와 같이 작성할 수도 있습니다. :</p>
+
+<pre class="brush: js notranslate">chooseToppings().then(placeOrder).then(collectOrder).then(eatPizza).catch(failureCallback);</pre>
+
+<p>그런데 이렇게 작성하면 읽기가 쉽지 않습니다. 사용자의 코드가 지금의 예제보다 더 복잡하다면 위의 방법은 사용하기 힘듭니다.</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: 다음 장에서 배울 <code>async</code>/<code>await</code> 문법으로 좀 더 간결화 할 수 있습니다.</p>
+</div>
+
+<p>Promise는 이벤트 리스너와 유사하지만 몇 가지 다른점이 있습니다. :</p>
+
+<ul>
+ <li>Promise는 한번에 성공/실패 중 하나의 결과값을 가집니다. 하나의 요청에 두 번 성공하고나 실패할 수 없습니다. 또한 이미 성공한 작업이 다시 실패로 돌아갈 수 없고 실패한 작업이 성공으로 돌아갈 수 없습니다.</li>
+ <li>If a promise has succeeded or failed and you later add a success/failure callback, the correct callback will be called, even though the event took place earlier.</li>
+</ul>
+
+<h2 id="Explaining_basic_promise_syntax_A_real_example">Explaining basic promise syntax: A real example</h2>
+
+<p>모던 웹 API는 잠재적으로 긴 작업을 수행하는 함수에 Promise를 사용하므로 Promise가 무엇인지 이해하는것은 매우 중요합니다. 현대적인 웹 기술을 사용하려면 Promise를 사용해야합니다. 챕터의 후반부에서 직접 Promise를 만들어보겠지만, 지금은 일단 웹 API에서 접할 수 있는 몇 가지 예제를 살펴보겠습니다.</p>
+
+<p>첫 번째로, 웹에서 이미지를 가져오기 위하여 <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch">fetch()</a></code> 메서드를 사용할 때 입니다.{{domxref("Body.blob", "blob()")}} 메서드는 fetch가 응답한 원시 body컨텐츠를 {{domxref("Blob")}} 오브젝트로 변환시켜주고{{htmlelement("img")}} 엘리먼트에 표현합니다. 이예제는 <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing#Asynchronous_JavaScript">first article of the series</a>유사합니다. 다만 Promise를 사용하기 위해 약간의 변경을 하겠습니다.</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: The following example will not work if you just run it directly from the file (i.e. via a <code>file://</code> URL). You need to run it through a <a href="/en-US/docs/Learn/Common_questions/set_up_a_local_testing_server">local testing server</a>, or use an online solution such as <a href="https://glitch.com/">Glitch</a> or <a href="/en-US/docs/Learn/Common_questions/Using_Github_pages">GitHub pages</a>.</p>
+</div>
+
+<ol>
+ <li>
+ <p>먼저 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">simple HTML template</a> 와 fetch할 이미지인 <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/coffee.jpg">sample image file</a> 을 다운받습니다.</p>
+ </li>
+ <li>
+ <p>HTML {{htmlelement("body")}} 하단에 {{htmlelement("script")}} 엘리먼트를 삽입합니다.</p>
+ </li>
+ <li>
+ <p>{{HTMLElement("script")}} 엘리먼트 안에 아래와 같이 코드를 작성합니다. :</p>
+
+ <pre class="brush: js notranslate">let promise = fetch('coffee.jpg');</pre>
+
+ <p><code>fetch()</code> 메서드를 호출하여, 네트워크에서 fetch할 이미지의 URL을 매개변수로 전달합니다. 두 번째 매개변수를 사용할 수 있지만, 지금은 우선 간단하게 하나의 매개변수만 사용하겠습니다. 코드를 더 살펴보면 <code>promise</code>변수에 <code>fetch()</code> 작업으로 반환된 Promise 오브젝트를 저장하고 있습니다. 이전에 말했듯이, 지금 오브젝트는 성공도 아니고 실패도 아닌 중간 상태를 저장하고 있습니다. 공식적으로는 <strong>pending</strong>상태라고 부릅니다.</p>
+ </li>
+ <li>
+ <p>작업이 성공적으로 진행될 때를 대응하기 위해 (이번 예제에선 {{domxref("Response")}} 가 반환될 때 입니다. ), 우리는 Promise 오브젝트의 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">.then()</a></code> 메서드를 호출합니다. <code>.then()</code> 블럭 안의 callback은 (<strong>executor </strong>라고 부름) Promise가 성공적으로 완료되고{{domxref("Response")}} 오브젝트를 반환할 때만 실행합니다. — 이렇게 성공한 Promise의 상태를 <strong>fulfilled</strong>라고 부릅니다. 그리고 반환된 {{domxref("Response")}} 오브젝트를 매개변수로 전달합니다.</p>
+
+ <div class="blockIndicator note">
+ <p><strong>Note</strong>: The way that a <code>.then()</code> block works is similar to when you add an event listener to an object using <code>AddEventListener()</code>. It doesn't run until an event occurs (when the promise fulfills). The most notable difference is that a .then() will only run once for each time it is used, whereas an event listener could be invoked multiple times.</p>
+ </div>
+
+ <p>그리고 즉시 <code>blob()</code> 메서드를 실행하여 Response Body가 완전히 다운로드 됐는지 확인합니다. 그리고 Response Body가 이용 가능할 때 추가 작업을 할 수 있는 <code>Blob</code> 오브젝트로 변환시킵니다. 해당 코드는 아래와 같이 작성할 수 있습니다. :</p>
+
+ <pre class="brush: js notranslate">response =&gt; response.blob()</pre>
+
+ <p>위의 코드는 아래의 코드를 축약한 형태입니다. </p>
+
+ <pre class="brush: js notranslate">function(response) {
+ return response.blob();
+}</pre>
+
+ <p>이제 추가 설명은 충븐하므로, JavaScript의 첫 번째 줄 아래에 다음과 같은 라인을 추가하세요.</p>
+
+ <pre class="brush: js notranslate">let promise2 = promise.then(response =&gt; response.blob());</pre>
+ </li>
+ <li>
+ <p>각 <code>.then()</code> 을 호출하면 새로운 Promise를 만드는데, 이는 매우 유용합니다. 왜냐하면 <code>blob()</code> 메서드도 Promise를 반환하기 때문에, 두 번째 Promise의 <code>.then()</code> 메서드를 호출함으로써 이행시 반환되는 <code>Blob</code> 오브젝트를 처리할 수 있습니다. 한 가지 메서드를 실행하여 결과를 반환하는 것보다 Blob에 좀 더 복잡한 일을 추가하고 싶습니다. 이럴때는 중괄호{ }로 묶습니다. (그렇지 않으면 에러가 발생합니다.).</p>
+
+ <p>이어서 아래와 같은 코드를 추가합니다.:</p>
+
+ <pre class="brush: js notranslate">let promise3 = promise2.then(myBlob =&gt; {
+
+})</pre>
+ </li>
+ <li>
+ <p>이제 executor 함수를 아래와 같이 채워넣습니다. 중괄호 안에 작성하면 됩니다. :</p>
+
+ <pre class="brush: js notranslate">let objectURL = URL.createObjectURL(myBlob);
+let image = document.createElement('img');
+image.src = objectURL;
+document.body.appendChild(image);</pre>
+
+ <p>여기서 우리는 두 번째 Promise가 fulfills일 때 반횐된 Blob을 매개변수로 전달받는 {{domxref("URL.createObjectURL()")}} 메서드를 실행하고 있습니다. 이렇게 하면 오브젝트가 가지고있는 URL이 반환됩니다. 그 다음 {{htmlelement("img")}} 엘리먼트를 만들고, 반환된 URL을 <code>src</code> 속성에 지정하여 DOM에 추가합니다. 이렇게 하면 페이지에 그림이 표시됩니다.</p>
+ </li>
+</ol>
+
+<p>If you save the HTML file you've just created and load it in your browser, you'll see that the image is displayed in the page as expected. Good work!</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: You will probably notice that these examples are somewhat contrived. You could just do away with the whole <code>fetch()</code> and <code>blob()</code> chain, and just create an <code>&lt;img&gt;</code> element and set its <code>src</code> attribute value to the URL of the image file, <code>coffee.jpg</code>. We did, however, pick this example because it demonstrates promises in a nice simple fashion, rather than for its real-world appropriateness.</p>
+</div>
+
+<h3 id="Responding_to_failure">Responding to failure</h3>
+
+<p>현재 에러가 발생했을 때 어떻게 처리를 해야할 지 작성된 코드가 없기때문에 코드를 조금만 더 추가하여 좀 더 완벽하게 작성해봅시다. (Promise에서 에러가 발생한 상태를 <strong>rejects</strong>라 부릅니다). 이전에 봤던대로 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch">.catch()</a></code> 블럭을 추가하여 오류를 핸들링 할 수 있습니다. 아래처럼 말이죠 :</p>
+
+<pre class="brush: js notranslate">let errorCase = promise3.catch(e =&gt; {
+ console.log('There has been a problem with your fetch operation: ' + e.message);
+});</pre>
+
+<p>에러 메시지를 확인하고 싶으면 잘못된 url을 지정해보세요, 개발자 도구 콘솔에서 에러를 확인할 수 있을것 입니다.</p>
+
+<p>물론 <code>.catch()</code> 블록 없이 코드를 작동시킬 수 있습니다. 하지만 좀 더 깊게 생각해보면 <code>.catch()</code> 블록이 없으면 어떤 에러가 발생했는지, 어떻게 해결해야 하는지 디버깅이 어렵습니다. 실제 앱에서 <code>.catch()</code> 을 사용하여 이미지 가져오기를 다시 실행하거나, 기본 이미지를 표시하는 등 작업을 지시할 수 있습니다.</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: You can see <a href="https://mdn.github.io/learning-area/javascript/asynchronous/promises/simple-fetch.html">our version of the example live</a> (see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/simple-fetch.html">source code</a> also).</p>
+</div>
+
+<h3 id="Chaining_the_blocks_together">Chaining the blocks together</h3>
+
+<p>위에서 사용한 코드는 작업이 어떻게 처리되는지 명확하게 보여주기 위해 매우 길게 코드를 작성했습니다. 이전 글에서 봤듯이, <code>.then()</code> 블럭을 사용하여 연쇄 작업을 진행할 수 있습니다. (또한 <code>.catch()</code> 블럭을 사용하여 에러 처리도 했지요). 앞선 예제의 코드는 아래와 같이 작성할 수도 있습니다. (see also <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/simple-fetch-chained.html">simple-fetch-chained.html</a> on GitHub):</p>
+
+<pre class="brush: js notranslate">fetch('coffee.jpg')
+.then(response =&gt; response.blob())
+.then(myBlob =&gt; {
+ let objectURL = URL.createObjectURL(myBlob);
+ let image = document.createElement('img');
+ image.src = objectURL;
+ document.body.appendChild(image);
+})
+.catch(e =&gt; {
+ console.log('There has been a problem with your fetch operation: ' + e.message);
+});</pre>
+
+<p>fulfilled promise 결과에 의해 반환된 값이 다음 <code>.then()</code> 블록의  executor 함수가 가진 파라미터로 전달 된다는 것을 꼭 기억하세요.</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: <code>.then()</code>/<code>.catch()</code> blocks in promises are basically the async equivalent of a <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/try...catch">try...catch</a></code> block in sync code. Bear in mind that synchronous <code>try...catch</code> won't work in async code.</p>
+</div>
+
+<h2 id="Promise_terminology_recap">Promise terminology recap</h2>
+
+<p>위의 섹션에서 다룬 내용은 정말 많습니다. 매우 중요한 내용을 다뤘으므로 개념을 명확히 이해하기 위해 몇번이고 다시 읽어보는게 좋습니다.</p>
+
+<ol>
+ <li>Promise가 생성되면 그 상태는 성공도 실패도 아닌 <strong>pending</strong>상태라고 부릅니다..</li>
+ <li>Promise결과가 반환되면 결과에 상관 없이 <strong>resolved</strong>상태라고 부릅니다..
+ <ol>
+ <li>성공적으로 처리된 Promise는 <strong>fulfilled</strong>상태이다. 이 상태가 되면 Promise 체인의 다음 <code>.then()</code> 블럭에서 사용할 수 있는 값을 반환합니다.. 그리고 <code>.then()</code> 블럭 내부의 executor 함수에 Promise에서 반환된 값이 파라미터로 전달됩니다..</li>
+ <li>실패한 Promise는 <strong>rejected</strong>상태이다. 이때 어떤 이유(<strong>reason)</strong> 때문에 Promise가 rejected 됐는지를 나타내는 에러 메시지를 포함한 결과가 반환됩니다. Promise 체이닝의 제일 마지막 <code>.catch()</code> 에서 상세한 에러 메시지를 확인할 수 있습니다.</li>
+ </ol>
+ </li>
+</ol>
+
+<h2 id="Running_code_in_response_to_multiple_promises_fulfilling">Running code in response to multiple promises fulfilling</h2>
+
+<p>위의 예제에서 Promise사용의 기초를 확인했습니다. 이제 고급 기능들을 한번 보겠습니다. 제일 먼저 확인해볼 예제는 다음과 같습니다. 연쇄적으로 일어나는 작업은 좋습니다. 그런데 모든 Promise가 fulfilled일 경우 코드를 실행하고 싶은 경우가 있을것 입니다.</p>
+
+<p>해당 기능을 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all">Promise.all()</a></code> 이라는 스테틱 메서드를 사용하여 만들 수 있습니다. 이 메서드는 Promise의 배열을 매개변수로 삼고, 배열의 모든 Promise가 fulfil일 때만 새로운 fulfil <code>Promise</code> 오브젝트를 반환합니다. 아래처럼 말이죠 :</p>
+
+<pre class="brush: js notranslate">Promise.all([a, b, c]).then(values =&gt; {
+ ...
+});</pre>
+
+<p>배열의 모든 Promise가 fulfil 이면, <code>.then()</code> 블럭의 executor 함수로의 매개변수로 Promise 결과의 배열을 전달합니다. <code>Promise.all()</code> 의 Promise의 배열 중 하나라도 reject라면, 전체 결과가 reject가 됩니다.</p>
+
+<p>이 방법은 매우 유용합니다. 웹 UI의 컨텐츠를 동적인 방법으로 채운다고 생각 해보겠습니다. 대부분 경우에 듬성듬성 내용을 채우기보단, 완전한 내용을 채울것 입니다.</p>
+
+<p>다른 예제를 만들어서 실행해 보겠습니다.</p>
+
+<ol>
+ <li>
+ <p>이미 만들어진 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">page template</a>을 다운받으세요 그리고 <code>&lt;/body&gt;</code> 뒤에 <code>&lt;script&gt;</code> 엘리먼트를 만들어주세요.</p>
+ </li>
+ <li>
+ <p>이미지 그리고 텍스트 파일(<a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/coffee.jpg">coffee.jpg</a>, <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/tea.jpg">tea.jpg</a>, and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/description.txt">description.txt</a>)을 다운받고 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">page template</a> 와 같은 경로에 저장해주세요.</p>
+ </li>
+ <li>
+ <p>먼저 Promise를 반환하는 몇 가지 함수를 만들어 <code>Promise.all()</code>로 결과를 반환합니다. 세 개의 <code>fetch()</code> 작업이 끝나고 다음 요청을 진행하고 싶다면 아래 코드처럼 <code>Promise.all()</code>블럭을 작성합니다. :</p>
+
+ <pre class="brush: js notranslate">let a = fetch(url1);
+let b = fetch(url2);
+let c = fetch(url3);
+
+Promise.all([a, b, c]).then(values =&gt; {
+ ...
+});</pre>
+
+ <p>Promise가 fulfilled가 됐을 때, fulfilment handler 핸들러로 전달된 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">values</span></font> 매개변수에는 각 <code>fetch()</code> 의 결과로 발생한 세 개의 <code>Response</code> 오브젝트가 들어있습니다 .</p>
+
+ <p>하지만 우리는 단순히 결과만 넘겨주고 싶지 않습니다. 우리는<code>fetch()</code> 언제 끝나는지 보다 불러온 데이터에 더 관심이 있습니다. 그말은 브라우저에 표현할 수 있는 Blob과 텍스트 문자열이 불러와 졌을 때 <code>Promise.all()</code> 블럭을 실행하고 싶다는 것 입니다.  <code>&lt;script&gt;</code> 엘리먼트에 아래와 같이 작성합니다. :</p>
+
+ <pre class="brush: js notranslate">function fetchAndDecode(url, type) {
+ return fetch(url).then(response =&gt; {
+ if (type === 'blob') {
+ return response.blob();
+ } else if (type === 'text') {
+ return response.text();
+ }
+ })
+ .catch(e =&gt; {
+ console.log('There has been a problem with your fetch operation: ' + e.message);
+ });
+}</pre>
+
+ <p>살짝 복잡해 보이므로 하나하나 살펴봅시다. :</p>
+
+ <ol>
+ <li>먼저 fetchAndDecode() 함수를 정의했고 함수의 매개변수로 컨텐츠의 URL과 가져오는 리소스의 타입을 지정합니다.</li>
+ <li>함수 내부에 첫 번째 예에서 본 것과 유사한 구조를 가진 코드가 있습니다. — <code>fetch()</code> 함수를 호출하여 전달받은 URL에서 리소스를 받아오도록 했습니다. 그리고 다음 Promise를 연쇄적으로 호출하여 디코딩된 (혹은 "읽은") Response Body를 반환하게 합니다. 이전 예에선 Blob만을 가져오기 때문에 <code>blob()</code> 메서드만 썼습니다.</li>
+ <li>여기에선 이전과 다른 두 가지가 있습니다. :
+ <ul>
+ <li>먼저 두 번째 Promise에서는 불러올 리소스의 <code>type</code> 이 무엇인지에 따라 반환받는 데이터가 다릅니다. executor 함수 내부에, 간단한 <code>if ... else if</code> 구문을 사용하여 어떤 종류의 파일을 디코딩해야 하는지에 따라 다른 Promise를 반환하게 했습니다. (이 경우 <code>blob</code> 이나 <code>text</code>밖에 없지만, 이것을 잘 활용하여 다른 코드에 확장하여 적용할 수 있습니다.).</li>
+ <li>두 번째로,  <code>fetch()</code> 호출 앞에 <code>return</code> 키워드를 추가했습니다. 이렇게 하면 Promise 체이닝의 마지막 결과값을 함수의 결과로 반환해 줄 수 있습니다. (이 경우 <code>blob()</code> 혹은 <code>text()</code>메서드에 의해 반환된 Promise 입니다.) 사실상 <code>fetch()</code> 앞의 <code>return</code> 구문은 체이닝 결과를 다시 상단으로 전달하는 행위 입니다.</li>
+ </ul>
+ </li>
+ <li>
+ <p>블럭의 마지막에는 <code>.catch()</code> 블럭을 추가하여 작업중 발생한 에러를 <code>.all()</code>의 배열로 전달합니다. 아무 Promise에서 reject가 발생하면, catch 블럭은 어떤 Promise에서 에러가 발생했는지 알려줄 것 입니다.  <code>.all()</code> (아래쪽에 있는) 블럭의 리소스에 문제가 있지 않는 이상 항상 fulfil일것 입니다. <code>.all</code> 블럭의 마지막 체이닝에 <code>.catch()</code> 블럭을 추가하여 reject됐을때 확인을 할 수 있습니다.</p>
+ </li>
+ </ol>
+
+ <p>함수의 body 안에 있는 코드는 비동기적이고 Promise 기반이므로, 전체 함수는 Promise로 작동합니다. — 편리하죠?.</p>
+ </li>
+ <li>
+ <p>다음으로 fetchAndDecode() 함수를 세 번 호출하여 이미지와 텍스트를 가져오고 디코딩 하는 과정을 시작합니다. 그리고 반환된 Promise를 각각의 변수에 저장합니다. 이전 코드에 이어서 아래 코드를 추가하세요. :</p>
+
+ <pre class="brush: js notranslate">let coffee = fetchAndDecode('coffee.jpg', 'blob');
+let tea = fetchAndDecode('tea.jpg', 'blob');
+let description = fetchAndDecode('description.txt', 'text');</pre>
+ </li>
+ <li>
+ <p>다음으로 위의 세 가지 코드가 모두 fulfilled가 됐을 때 원하는 코드를 실행하기 위해 <code>Promise.all()</code> 블럭을 만듭니다. 우선, <code>.then()</code> call 안에 비어있는 executor 를 추가하세요 :</p>
+
+ <pre class="brush: js notranslate">Promise.all([coffee, tea, description]).then(values =&gt; {
+
+});</pre>
+
+ <p>위에서 Promise를 포함하는 배열을 매개 변수로 사용하는 것을 확인할 수 있습니다. executor는 세 가지 Promise가 resolve될 때만 실행될 것 입니다. 그리고 executor가 실행될 때 개별적인 Promise의 결과를 포함하는 [coffee-results, tea-results, description-results] 배열을 매개 변수로 전달받을 것 입니다.  (여기선 디코딩된 Response Body 입니다.).</p>
+ </li>
+ <li>
+ <p>마지막으로 executor 함수를 작성합니다. 예제에선 반환된 결과를 별도의 변수로 저장하기 위해 간단한 동기화 코드를 사용합니다. (Blob에서 오브젝트 URLs 생성), 그리고 페이지에 텍스트와 이미지를 표시합니다.</p>
+
+ <pre class="brush: js notranslate">console.log(values);
+// Store each value returned from the promises in separate variables; create object URLs from the blobs
+let objectURL1 = URL.createObjectURL(values[0]);
+let objectURL2 = URL.createObjectURL(values[1]);
+let descText = values[2];
+
+// Display the images in &lt;img&gt; elements
+let image1 = document.createElement('img');
+let image2 = document.createElement('img');
+image1.src = objectURL1;
+image2.src = objectURL2;
+document.body.appendChild(image1);
+document.body.appendChild(image2);
+
+// Display the text in a paragraph
+let para = document.createElement('p');
+para.textContent = descText;
+document.body.appendChild(para);</pre>
+ </li>
+ <li>
+ <p>코드를 저장하고 창을 새로고치면 보기엔 좋지 않지만, UI 구성 요소가 모두 표시된 것을 볼 수 있습니다.</p>
+ </li>
+</ol>
+
+<p>여기서 제공한 코드는 매우 기초적이지만, 내용을 전달하기에는 아주 좋습니다..</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: If you get stuck, you can compare your version of the code to ours, to see what it is meant to look like — <a href="https://mdn.github.io/learning-area/javascript/asynchronous/promises/promise-all.html">see it live</a>, and see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/promise-all.html">source code</a>.</p>
+</div>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: If you were improving this code, you might want to loop through a list of items to display, fetching and decoding each one, and then loop through the results inside <code>Promise.all()</code>, running a different function to display each one depending on what the type of code was. This would make it work for any number of items, not just three.</p>
+
+<p>Also, you could determine what the type of file is being fetched without needing an explicit <code>type</code> property. You could, for example, check the {{HTTPHeader("Content-Type")}} HTTP header of the response in each case using <code><a href="/en-US/docs/Web/API/Headers/get">response.headers.get("content-type")</a></code>, and then react accordingly.</p>
+</div>
+
+<h2 id="Running_some_final_code_after_a_promise_fulfillsrejects">Running some final code after a promise fulfills/rejects</h2>
+
+<p>Promise의 결과가 fulfilled 인지 rejected인지 관계 없이 Promise가 완료된 후 최종 코드 블럭을 실행하려는 경우가 있을 것입니다. 이전에는 아래 예시처럼 <code>.then()</code> 블럭과<code>.catch()</code> 블럭의 callbacks에 아래와 같이 runFinalCode()를 넣었었습니다. :</p>
+
+<pre class="brush: js notranslate">myPromise
+.then(response =&gt; {
+ doSomething(response);
+ runFinalCode();
+})
+.catch(e =&gt; {
+ returnError(e);
+ runFinalCode();
+});</pre>
+
+<p>보다 최근의 현대 브라우저에서는 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally">.finally()</a></code> 메서드를 사용할 수 있습니다. 이 메서드를 Promise 체이닝의 끝에 배치하여 코드 반복을 줄이고 좀 더 우아하게 일을 처리할 수 있습니다. 아래와 같이 마지막 블럭에 적용할 수 있습니다. :</p>
+
+<pre class="brush: js notranslate">myPromise
+.then(response =&gt; {
+ doSomething(response);
+})
+.catch(e =&gt; {
+ returnError(e);
+})
+.finally(() =&gt; {
+ runFinalCode();
+});</pre>
+
+<p>실제 예시는 <a href="https://mdn.github.io/learning-area/javascript/asynchronous/promises/promise-finally.html">promise-finally.html demo</a> 에 나와있습니다. (see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/promise-finally.html">source code</a> also). 이 예시는 위에서 만들어본 <code>Promise.all()</code> 데모와 똑같이 작동합니다. 다만 이번에는 <code>fetchAndDecode()</code> 함수에 다음 연쇄 작업으로 <code>finally()</code> 를 호출합니다.:</p>
+
+<pre class="brush: js notranslate">function fetchAndDecode(url, type) {
+ return fetch(url).then(response =&gt; {
+ if(type === 'blob') {
+ return response.blob();
+ } else if(type === 'text') {
+ return response.text();
+ }
+ })
+ .catch(e =&gt; {
+ console.log(`There has been a problem with your fetch operation for resource "${url}": ` + e.message);
+ })
+ .finally(() =&gt; {
+ console.log(`fetch attempt for "${url}" finished.`);
+ });
+}</pre>
+
+<p>이 로그는 각 fetch시도가 완료되면 콘솔에 메시지를 출력하여 사용자에게 알려줍니다.</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: <code>then()</code>/<code>catch()</code>/<code>finally()</code> is the async equivalent to <code>try</code>/<code>catch</code>/<code>finally</code> in sync code.</p>
+</div>
+
+<h2 id="Building_your_own_custom_promises">Building your own custom promises</h2>
+
+<p>여기까지 오느라 수고하셨습니다. 여기까지 오면서 우리는 Promise를 직접 만들어봤습니다. 여러 개의 Promise를 <code>.then()</code> 을 사용하여 체이닝 하거나 사용자 정의함수를 조합하여, 비동기 Promise기반 함수를 만들었습니다. 이전에 만든 <code>fetchAndDecode()</code> 함수가 이를 잘 보여주고있죠.</p>
+
+<p>다양한 Promise 기반 API를 결합하여 사용자 정의 함수를 만드는 것은, Promise와 함께 원하는 기능을 만드는 가장 일반적인 방법이며, 대부분 모던 API는 이와 같은 원리를 기반으로 만들어지고 있습니다. 그리고 또 다른 방법이 있습니다.</p>
+
+<h3 id="Using_the_Promise_constructor">Using the Promise() constructor</h3>
+
+<p><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise()</a></code> constructor를 사용하여 사용자 정의 Promise를 만들 수 있습니다. 주로 Promise기반이 아닌 구식 비동기 API코드를 Promise기반 코드로 만들고 싶을 경우 사용합니다. 이 방법은 구식 프로젝트 코드, 라이브러리, 혹은 프레임워크를 지금의 Promise 코드와 함께 사용할 때 유용합니다.</p>
+
+<p>간단한 예를 들어 살펴보겠습니다. — 여기 Promise와 함께 사용되는 <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout">setTimeout()</a></code> 호출이 있습니다. — 이 함수는 2초 후에 "Success!"라는 문자열과 함께 resolve됩니다. (통과된 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve">resolve()</a></code> 호출에 의해);</p>
+
+<pre class="brush: js notranslate">let timeoutPromise = new Promise((resolve, reject) =&gt; {
+ setTimeout(function(){
+ resolve('Success!');
+ }, 2000);
+});</pre>
+
+<p><code>resolve()</code> 와<code>reject()</code> 는 Promise의 fulful / reject일때의 일을 수행하기 위해 호출한 함수입니다. 이번의 경우 Promise는 "Success!"문자와 함께 fulfill 됐습니다.</p>
+
+<p>따라서 이 Promise를 호출할 때, 그 끝에 <code>.then()</code> 블럭을 사용하면 "Success!" 문자열이 전달될 것입니다. 아래 코드는 간단한 alert메시지를 출력하는 방법 입니다. :</p>
+
+<pre class="brush: js notranslate">timeoutPromise
+.then((message) =&gt; {
+ alert(message);
+})</pre>
+
+<p>혹은 아래처럼 쓸 수 있죠</p>
+
+<pre class="brush: js notranslate">timeoutPromise.then(alert);
+</pre>
+
+<p>Try <a href="https://mdn.github.io/learning-area/javascript/asynchronous/promises/custom-promise.html">running this live</a> to see the result (also see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/custom-promise.html">source code</a>).</p>
+
+<p>위의 예시는 유연하게 적용된 예시가 아닙니다. — Promise는 항산 하나의 문자열로만 fulfil됩니다. 그리고 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject">reject()</a></code> 조건도 정의되어있지 않습니다. (사실, <code>setTimeout()</code> 은 실패 조건이 필요없습니다, 그러니 이 예제에서는 없어도 됩니다.).</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: Why <code>resolve()</code>, and not <code>fulfill()</code>? The answer we'll give you, for now, is <em>it's complicated</em>.</p>
+</div>
+
+<h3 id="Rejecting_a_custom_promise">Rejecting a custom promise</h3>
+
+<p><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject">reject()</a></code> 메서드를 사용하여 Promise가 reject상태일 때 전달할 값을 지정할 수 있습니다. —  <code>resolve()</code>와 똑같습니다. 여기엔 하나의 값만 들어갈 수 있습니다. Promise가 reject 되면 에러는 <code>.catch()</code> 블럭으로 전달됩니다.</p>
+
+<p>이전 예시를 좀 더 확장하여 <code>reject()</code> 을 추가하고, Promise가 fulfil일 때 다른 메시지도 전달할 수 있게 만들어봅시다.</p>
+
+<p>이전 예시 <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/custom-promise.html">previous example</a>를 복사한 후 이미 있는 <code>timeoutPromise()</code> 함수를 아래처럼 정의해주세요. :</p>
+
+<pre class="brush: js notranslate">function timeoutPromise(message, interval) {
+ return new Promise((resolve, reject) =&gt; {
+ if (message === '' || typeof message !== 'string') {
+ reject('Message is empty or not a string');
+ } else if (interval &lt; 0 || typeof interval !== 'number') {
+ reject('Interval is negative or not a number');
+ } else {
+ setTimeout(function(){
+ resolve(message);
+ }, interval);
+ }
+ });
+};</pre>
+
+<p>함수를 살펴보면 두 가지 매개변수가 있습니다. — 출력할 메시지와(<font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">message</span></font>) 메시지를 출력할 때 까지 기다릴 시간(<code>interval</code>)입니다. 맨 위에 <code>Promise</code> 오브젝트를 반환하도록 되어있습니다. 따라서 함수를 실행하면 우리가 사용하고 싶은 Promise가 반환될 것 입니다..</p>
+
+<p>Promise constructor 안에는 몇가지 사항을 확인하기 위해 <code>if ... else</code> 구문이 있습니다. :</p>
+
+<ol>
+ <li>첫번째로 메시지의 유효성을 검사합니다. 메시지가 비어있거나 문자가 아닌 경우, 에러 메시지와 함께 Promise를 reject합니다.</li>
+ <li>그 다음으로 interval의 유효성을 검사합니다. 숫자가 아니거나 음수일 경우, 에러 메시지와 함께 Promise를 reject합니다.</li>
+ <li>마지막은 항목은, 두 매개변수를 확인하여 유효할 경우 <code>setTimeout()</code>함수에 지정된 interval에 맞춰 Promise를 resolve합니다.</li>
+</ol>
+
+<p><code>timeoutPromise()</code> 함수는 <code>Promise</code>를 반환하므로,  <code>.then()</code>, <code>.catch()</code>, 기타등등 을 사용해 Promise 체이닝을 만들 수 있습니다. 아래와 같이 작성해봅시다. — 기존에 있는 <code>timeoutPromise</code> 를 삭제하고 아래처럼 바꿔주세요. :</p>
+
+<pre class="brush: js notranslate">timeoutPromise('Hello there!', 1000)
+.then(message =&gt; {
+ alert(message);
+})
+.catch(e =&gt; {
+ console.log('Error: ' + e);
+});</pre>
+
+<p>이 코드를 저장하고 브라우저를 새로 고침하면 1초 후에 'Hello there!' alert가 출력될 것 입니다. 이제 메시지 내용을 비우거나 interval을 음수로 지정해보세요 그렇게 하면 Promise가 reject되며 에러 메시지를 콘솔에 출력해 줄 것입니다. 또한 resolved 메시지를 다르게 만들어 줄 수도 있습니다.</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: You can find our version of this example on GitHub as <a href="https://mdn.github.io/learning-area/javascript/asynchronous/promises/custom-promise2.html">custom-promise2.html</a> (see also the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/custom-promise2.html">source code</a>).</p>
+</div>
+
+<h3 id="A_more_real-world_example">A more real-world example</h3>
+
+<p>위의 예제는 개념을 이해하기 쉽게 단순하게 만들었지만, 실제로 그다지 비동기적이지는 않습니다. 억지로 비동기적 작업을 구현하기 위해 <code>setTimeout()</code>을 사용하여 함수를 만들었지만 사용자 정의 Promise를 만들고 에러를 다루기엔 충분한 예제였습니다.</p>
+
+<p>좀 더 공부해볼 추가내용을 소개해주고 싶습니다. 바로 <a href="https://github.com/jakearchibald/idb/">Jake Archibald's idb library</a>입니다 이 라이브러리는 <code>Promise()</code> constructor의 비동기작업 응용을 보여주는 유용한 라이브러리 입니다. 클라이언트측에서 데이터를 저장하고 검색하기 위한 구식 callback 기반 API로 Promise와 함께 사용하는 <a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB API</a>입니다. <a href="https://github.com/jakearchibald/idb/blob/master/lib/idb.js">main library file</a>을 살펴보면 우리가 지금까지 다뤄본것과 같은 종류의 테크닉을 볼 수 있습니다. 아래 코드 블록은 basic request model이 Promise를 사용하게끔 변환해 주는 IndexedDB 메서드 입니다. :</p>
+
+<pre class="brush: js notranslate">function promisifyRequest(request) {
+ return new Promise(function(resolve, reject) {
+ request.onsuccess = function() {
+ resolve(request.result);
+ };
+
+ request.onerror = function() {
+ reject(request.error);
+ };
+ });
+}</pre>
+
+<p>우리가 했던것 처럼 적절한 타이밍에 Promise를 fulfil하고 reject하는 이벤트 핸들러를 두 개 추가했습니다. :</p>
+
+<ul>
+ <li><code><a href="/en-US/docs/Web/API/IDBRequest">request</a></code>의 <a href="/en-US/docs/Web/API/IDBRequest/success_event"><code>success</code> event</a>가 실행될 때, <code><a href="/en-US/docs/Web/API/IDBRequest/onsuccess">onsuccess</a></code> 핸들러에 의해 fulfill된 Promise의 request <code><a href="/en-US/docs/Web/API/IDBRequest/result">result</a></code>를 반환한다.</li>
+ <li>반면 <code><a href="/en-US/docs/Web/API/IDBRequest">request</a></code>'s <a href="/en-US/docs/Web/API/IDBRequest/error_event"><code>error</code> event</a>가 실행되면 <code><a href="/en-US/docs/Web/API/IDBRequest/onerror">onerror</a></code> 핸들러에 의해 reject된 Promise의 request <code><a href="/en-US/docs/Web/API/IDBRequest/error">error</a></code>를 반환한다.</li>
+</ul>
+
+<h2 id="Conclusion">Conclusion</h2>
+
+<p>Promises are a good way to build asynchronous applications when we don’t know the return value of a function or how long it will take to return. They make it easier to express and reason about sequences of asynchronous operations without deeply nested callbacks, and they support a style of error handling that is similar to the synchronous <code>try...catch</code> statement.</p>
+
+<p>Promises work in the latest versions of all modern browsers; the only place where promise support will be a problem is in Opera Mini and IE11 and earlier versions.</p>
+
+<p>We didn't touch on all promise features in this article, just the most interesting and useful ones. As you start to learn more about promises, you'll come across further features and techniques.</p>
+
+<p>Most modern Web APIs are promise-based, so you'll need to understand promises to get the most out of them. Among those APIs are <a href="/en-US/docs/Web/API/WebRTC_API">WebRTC</a>, <a href="/en-US/docs/Web/API/Web_Audio_API">Web Audio API</a>, <a href="/en-US/docs/Web/API/Media_Streams_API">Media Capture and Streams</a>, and many more. Promises will be more and more important as time goes on, so learning to use and understand them is an important step in learning modern JavaScript.</p>
+
+<h2 id="See_also">See also</h2>
+
+<ul>
+ <li><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise()</a></code></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Using_promises">Using promises</a></li>
+ <li><a href="https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html">We have a problem with promises</a> by Nolan Lawson</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Timeouts_and_intervals", "Learn/JavaScript/Asynchronous/Async_await", "Learn/JavaScript/Asynchronous")}}</p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">General asynchronous programming concepts</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Introducing asynchronous JavaScript</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">Cooperative asynchronous JavaScript: Timeouts and intervals</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Graceful asynchronous programming with Promises</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">Making asynchronous programming easier with async and await</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">Choosing the right approach</a></li>
+</ul>
diff --git a/files/ko/learn/javascript/asynchronous/timeouts_and_intervals/index.html b/files/ko/learn/javascript/asynchronous/timeouts_and_intervals/index.html
new file mode 100644
index 0000000000..1f3d4f2a6a
--- /dev/null
+++ b/files/ko/learn/javascript/asynchronous/timeouts_and_intervals/index.html
@@ -0,0 +1,598 @@
+---
+title: 'Cooperative asynchronous JavaScript: Timeouts and intervals'
+slug: Learn/JavaScript/Asynchronous/Timeouts_and_intervals
+translation_of: Learn/JavaScript/Asynchronous/Timeouts_and_intervals
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Introducing", "Learn/JavaScript/Asynchronous/Promises", "Learn/JavaScript/Asynchronous")}}</div>
+
+<p class="summary">이 장에서는 자바스크립트가 설정된 시간이 경과하거나 혹은 정해진 시간 간격(예 : 초당 설정된 횟수)으로 비동기 코드를 작동하는 전형적인 방법을 살펴본다. 그리고 이 방법들이 어떤 것에 유용한지 얘기해 보고, 그 본질적인 문제에 대해 살펴본다.</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Prerequisites:</th>
+ <td>Basic computer literacy, a reasonable understanding of JavaScript fundamentals.</td>
+ </tr>
+ <tr>
+ <th scope="row">Objective:</th>
+ <td>To understand asynchronous loops and intervals and what they are useful for.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Introduction">Introduction</h2>
+
+<p>오랜 시간 동안 웹플랫폼은 자바스크립트 프로그래머가 일정한 시간이 흐른 뒤에 비동기적 코드를 실행할 수 있게하는 다양한 함수들을 제공해 왔다. 그리고 프로그래머가 중지시킬 때까지 코드 블록을 반복적으로 실행하기 위한 다음과 같은 함수들이 있다.</p>
+
+<dl>
+ <dt><code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout">setTimeout()</a></code></dt>
+ <dd>특정 시간이 경과한 뒤에 특정 코드블록을 한번 실행한다.</dd>
+ <dt></dt>
+ <dt><code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval">setInterval()</a></code></dt>
+ <dd>각각의 호출 간에 일정한 시간 간격으로 특정 코드블록을 반복적으로 실행한다.</dd>
+ <dt><code><a href="/en-US/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame()</a></code></dt>
+ <dd>setInterval()의 최신 버전; 그 코드가 실행되는 환경에 관계없이 적절한 프레임 속도로 애니메이션을 실행시키면서, 브라우저가 다음 화면을 보여주기 전에 특정 코드블록을 실행한다.</dd>
+</dl>
+
+<p>이 함수들에 의해 설정된 비동기 코드는 메인 스레드에서 작동한다. 그러나 프로세서가 이러한 작업을 얼마나 많이 수행하는지에 따라, 코드가 반복되는 중간에 다른 코드를 어느 정도 효율적으로 실행할 수 있다. 어쨌든 이러한 함수들은 웹사이트나 응용 프로그램에서 일정한 애니메이션 및 기타 배경 처리를 실행하는 데 사용된다. 다음 섹션에서는 그것들을 어떻게 사용할 수 있는지 보여줄 것이다.</p>
+
+<h2 id="setTimeout">setTimeout()</h2>
+
+<p>앞에서 언급했듯이 setTimeout ()은 지정된 시간이 경과 한 후 특정 코드 블록을 한 번 실행한다. 그리고 다음과 같은 파라미터가 필요하다.:</p>
+
+<ul>
+ <li>실행할 함수 또는 다른 곳에 정의 된 함수 참조.</li>
+ <li>코드를 실행하기 전에 대기 할 밀리세컨드 단위의 시간 간격 (1000밀리세컨드는 1 초)을 나타내는 숫자. 값을 0으로 지정하면(혹은 이 값을 모두 생략하면) 함수가 즉시 실행된다. 왜 이 파라미터를 수행해야 하는지도 좀 더살펴 볼 것이다. </li>
+ <li>함수가 실행될 때 함수에 전달해야할 파라미터를 나타내는 0이상의 값.</li>
+</ul>
+
+<div class="blockIndicator note">
+<p><strong>Note:</strong> 타임아웃 콜백은 단독으로 실행되지 않기 때문에 지정된 시간이 지난 그 시점에 정확히  콜백 될 것이라는 보장은 없다. 그보다는 최소한 그 정도의 시간이 지난 후에 호출된다. 메인 스레드가 실행해야 할 핸들러를 찾기 위해 이런 핸들러들을 살펴보는 시점에 도달할 때까지 타임아웃 핸들러를 실행할 수 없다.</p>
+</div>
+
+<p>아래 예제에서 브라우저는 2분이 지나면 익명의 함수를 실행하고 경보 메시지를 띄울 것이다. (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/simple-settimeout.html">see it running live</a>, and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/simple-settimeout.html">see the source code</a>):</p>
+
+<pre class="brush: js">let myGreeting = setTimeout(function() {
+ alert('Hello, Mr. Universe!');
+}, 2000)</pre>
+
+<p>지정한 함수가 꼭 익명일 필요는 없다. 함수에 이름을 부여 할 수 있고, 다른 곳에서 함수를 정의하고 setTimeout ()에 참조(reference)를 전달할 수도 있다. 아래 코드는 위의 코드와 같은 실행 결과를 얻을 수 있다. </p>
+
+<pre class="brush: js">// With a named function
+let myGreeting = setTimeout(function sayHi() {
+ alert('Hello, Mr. Universe!');
+}, 2000)
+
+// With a function defined separately
+function sayHi() {
+ alert('Hello Mr. Universe!');
+}
+
+let myGreeting = setTimeout(sayHi, 2000);</pre>
+
+<p>예를 들자면 timeout 함수와 이벤트에 의해 중복 호출되는 함수를 사용하려면 이 방법이 유용할 수 있다. 이 방법은 코드라인을 깔끔하게  정리하는 데 도움을 준다. 특히 timeout 콜백의 코드라인이 여러 줄이라면 더욱 그렇다.  </p>
+
+<p>setTimeout ()은 나중에 타임아웃을 할 경우에 타임아웃을 참조하는데 사용하는 식별자 값을 리턴한다.  그 방법을 알아 보려면 아래{{anch("Clearing timeouts")}}을 참조하세요.</p>
+
+<h3 id="setTimeout_함수에_매개변수parameter_전달">setTimeout () 함수에 매개변수(parameter) 전달</h3>
+
+<p>setTimeout () 내에서 실행되는 함수에 전달하려는 모든 매개변수는 setTimeout () 매개변수 목록 끝에 추가하여 전달해야 한다. 아래 예제처럼, 이전 함수를 리팩터링하여 전달된 매개변수의 사람 이름이 추가된 문장을 표시할 수 있다.</p>
+
+<pre class="brush: js">function sayHi(who) {
+ alert('Hello ' + who + '!');
+}</pre>
+
+<p>Say hello의 대상이 되는 사람이름은 <code>setTimeout()의 세번째 매개변수로 함수에 전달된다.</code></p>
+
+<pre class="brush: js">let myGreeting = setTimeout(sayHi, 2000, 'Mr. Universe');</pre>
+
+<h3 id="timeout_취소">timeout 취소</h3>
+
+<p>마지막으로 타임아웃이 생성되면(setTimeout()이 실행되면) 특정시간이 경과하기 전에 <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearTimeout">clearTimeout()</a></code>을 호출하여 타임아웃을 취소할 수 있다.  <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearTimeout">clearTimeout()</a></code>은  <code>setTimeout()</code>콜의 식별자를 매개변수로  <code>setTimeout()</code>에 전달한다. 위 예제의 타임아웃을 취소하려면 아래와 같이 하면 된다.</p>
+
+<pre class="brush: js">clearTimeout(myGreeting);</pre>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: 인사를 할 사람의 이름을 설정하고 별도의 버튼을 사용하여 인사말을 취소 할 수있는 약간 더 복잡한 폼양식 예제인  <a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/greeter-app.html">greeter-app.html</a> 을 참조하세요.</p>
+</div>
+
+<h2 id="setInterval">setInterval()</h2>
+
+<p>setTimeout ()은 일정 시간이 지난 후 코드를 한 번 실행해야 할 때 완벽하게 작동합니다. 그러나 애니메이션의 경우와 같이 코드를 반복해서 실행해야 할 경우 어떨까요?</p>
+
+<p>이럴 경우에 setInterval ()이 필요합니다. setInterval ()은 setTimeout ()과 매우 유사한 방식으로 작동합니다. 다만 setTimeout ()처럼 첫 번째 매개 변수(함수)가 타임아웃 후에 한번 실행되는게 아니라 두 번째 매개 변수에 주어진 시간까지 반복적으로 실행되는 것이 차이점입니다.  setInterval() 호출의 후속 파라미터로 실행 중인 함수에 필요한 파라미터를 전달할 수도 있다.</p>
+
+<p>예를 들어 봅시다. 다음 함수는 새 Date() 객체를 생성한 후에 ToLocaleTimeString()을 사용하여 시간데이터를 문자열로 추출한 다음 UI에 표시합니다. 그리고 setInterval()을 사용하여 초당 한 번 함수(displayTime)를 실행하면 초당 한 번 업데이트되는 디지털 시계와 같은 효과를 만들어냅니다.(<a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/setinterval-clock.html">see this live</a>, and also <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/setinterval-clock.html">see the source</a>): </p>
+
+<pre class="brush: js">function displayTime() {
+ let date = new Date();
+ let time = date.toLocaleTimeString();
+ document.getElementById('demo').textContent = time;
+}
+
+const createClock = setInterval(displayTime, 1000);</pre>
+
+<p>setTimeout()과 같이 setInterval()도 식별자 값을 리턴하여 나중에 interval을 취소해야 할 때 사용한다.</p>
+
+<h3 id="interval_취소">interval 취소</h3>
+
+<p>setInterval ()은 아무 조치를 취하지 않으면 끊임없이 계속 실행됩니다. 이 상태를 중지하는 방법이 필요합니다. 그렇지 않으면 브라우저가 추가 작업을 완료 할 수 없거나, 현재 처리 중인 애니메이션이 완료되었을 때 오류가 발생할 수 있습니다. setTimeout()과 같은 방식으로 setInterval () 호출에 의해 반환 된 식별자를 clearInterval () 함수에 전달하여 이 작업을 취소할수 있습니다.</p>
+
+<pre class="brush: js">const myInterval = setInterval(myFunction, 2000);
+
+clearInterval(myInterval);</pre>
+
+<h4 id="능동학습_자신만의_스톱워치를_만들기.">능동학습 : 자신만의 스톱워치를 만들기.</h4>
+
+<p>위에서 모두 설명해 드렸으니, 과제를 드리겠습니다. <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/setinterval-clock.html">setInterval-clock.html</a> 예제를 수정하여 자신만의 간단한 스톱워치를 만들어 보세요.</p>
+
+<p>위에서 설명(디지털 시계)한 것처럼 시간을 표시해야 하고, 이 예제에서는 아래 기능을 추가하세요.</p>
+
+<ul>
+ <li>스톱워치를 실행시키는 "Start" 버튼. </li>
+ <li>일시정지나 종료시키는 "Stop" 버튼.</li>
+ <li>시간을 0으로 설정하는 "Reset" 버튼.</li>
+ <li>실제 시간을 표시하지 말고 경과된 시간을 초단위로 표시..</li>
+</ul>
+
+<p>몇가지 힌트를 드립니다.</p>
+
+<ul>
+ <li>버튼 마크업은 여러분이 원하는 대로 구성하고 스타일링 하세요. 자바스크립트 버튼 레퍼런스를 가져올 수 있는 후크를 포함한 semantic HTML을 사용하세요.</li>
+ <li> 0에서 시작하여 상수 루프를 이용하여 1 초 단위로 증가하는 변수를 작성해 보세요.</li>
+ <li>앞서 설명한 Date () 객체를 사용하지 않고 이 예제를 작성하는 것이 더 쉽지만 정확도는 떨어집니다. 정확히 1000ms 후에 콜백이 시작된다고 보장 할 수는 없기 때문입니다. 보다 정확한 방법은 startTime = Date.now ()를 실행하여 사용자가 시작 버튼을 클릭했을 때 정확한 timestamp을 얻은 다음 Date.now ()-startTime을 실행하여 시간(milliseconds)을 얻어 냅니다.</li>
+ <li>시, 분, 초 단위의 시간을 별도의 변수를 통해 계산한 다음 각 루프 반복 후에 문자열로 함께 표시해 보세요. 두 번째 카운터에서 하나씩 해결할 수 있습니다.</li>
+ <li>어떻게 계산할 것인지 생각해 봅시다.
+ <ul>
+ <li>1시간은 3600초 입니다.</li>
+ <li>분단위 시간은 시간을 60으로 나눈 값에서 시간단위를 제거한 값입니다. 그리고 초단위 시간은 그 값에서 분단위 시간을 제거한 값입니다(예 :3700초를 60초로 나누면 3600초(시단위) + 100초(분단위), 분단위를 다시 60으로 나누면 60초(분단위) + 40초(초단위))</li>
+ </ul>
+ </li>
+ <li>시간값이 10밀리세컨드이하면 화면의 시간을 0으로 표시하세요. 더 일반적인 시계처럼 보일 겁니다.</li>
+ <li>스톱워치를 정지시키기 위해 interval을 취소해 보세요. 스톱워치를 리셋하기 위해 시간 카운터를 0으로 설정하고, interval을 취소한 후에 화면을 즉시 업데이트 하세요.</li>
+ <li>스타트 버튼이 클릭되면 버튼을 즉시 비활성화 시키고 스톱/리셋버튼이 클릭되면 다시 활성화해 보세요. 그렇지 않고 스타트 버튼이 여러번 클릭되면 setInterval()이 중복 실행되어서 실행 오류가 발생할 수 있습니다.</li>
+</ul>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: If you get stuck, you can <a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/setinterval-stopwatch.html">find our version here</a> (see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/setinterval-stopwatch.html">source code</a> also).</p>
+</div>
+
+<h2 id="setTimeout과_setInterval에서_주의해야할_것_들">setTimeout()과 setInterval()에서 주의해야할 것 들</h2>
+
+<p>setTimeout()과 setInterval()에는 몇가지 주의해야 할 것들이 있습니다. 어떤 것인지 한번 살펴보겠습니다.</p>
+
+<h3 id="순환_timeouts">순환 timeouts</h3>
+
+<p>setTimeout()을 사용하는 또 다른 방법입니다. 바로 setInterval()을 사용하는 대신 setTimeout()을 이용해 같은코드를 반복적으로 실행시키는 방법입니다.</p>
+
+<p>The below example uses a recursive <code>setTimeout()</code> to run the passed function every 100 milliseconds: 아래 예제에서는 setTimeout()이 주어진 함수를 100밀리세컨드마다 실행합니다.</p>
+
+<pre class="brush: js">let i = 1;
+
+setTimeout(function run() {
+ console.log(i);
+ i++;
+ setTimeout(run, 100);
+}, 100);</pre>
+
+<p>위 예제를 아래 예제와 비교해 보세요. 아래 예제는 setInterval()을 사용하여 같은 결과를 얻을 수 있습니다.</p>
+
+<pre class="brush: js">let i = 1;
+
+setInterval(function run() {
+ console.log(i);
+ i++
+}, 100);</pre>
+
+<h4 id="그렇다면_순환_setTimeout과_setInterval은_어떻게_다를까요">그렇다면 순환 setTimeout()과 setInterval()은 어떻게 다를까요?</h4>
+
+<p>두 방법의 차이는 미묘합니다.</p>
+
+<ul>
+ <li>순환 setTimeout ()은 실행과 실행 사이에 동일한 지연을 보장합니다.  위의 경우 100ms입니다. 코드가 실행 된 후 다시 실행되기 전에 100 ms 동안 대기하므로 간격은 코드 실행 시간에 관계없이 동일합니다.</li>
+ <li>setInterval ()을 사용하는 예제는 약간 다르게 작동합니다. 설정된 간격에는 실행하려는 코드를 실행하는 데 걸리는 시간이 포함됩니다. 코드를 실행하는 데 40ms가 걸리다면 간격이 60ms에 불과합니다.</li>
+ <li>setTimeout ()을 재귀적으로 사용할 때 각 반복은 다음 반복을 실행하기 전에 또 하나의 대기시간을 설정합니다. 즉, setTimeout ()의 두 번째 매개 변수의 값은 코드를 다시 실행하기 전에 대기 할 또 하나의 시간을 지정합니다.</li>
+</ul>
+
+<p>코드가 지정한 시간 간격보다 실행 시간이 오래 걸리면 순환 setTimeout ()을 사용하는 것이 좋습니다. 이렇게하면 코드 실행 시간에 관계없이 실행 간격이 일정하게 유지되어 오류가 발생하지 않습니다.</p>
+
+<h3 id="즉시_timeouts">즉시 timeouts</h3>
+
+<p>setTimeout()의 값으로 0을 사용하면 메인 코드 스레드가 실행된 후에 가능한 한 빨리 지정된 콜백 함수의 실행을 예약할 수 있다.</p>
+
+<p>예를 들어 아래 코드 (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/zero-settimeout.html">see it live</a>) 는 "Hello"가 포함된 alert를 출력 한 다음 첫 번째 경고에서 OK를 클릭하자마자 "World"가 포함된 alert를 출력합니다.</p>
+
+<pre class="brush: js">setTimeout(function() {
+ alert('World');
+}, 0);
+
+alert('Hello');</pre>
+
+<p>이것은 모든 메인 스레드의 실행이 완료되자마자 실행되도록 코드 블록을 설정하려는 경우 유용할 할 수 있습니다. 비동기 이벤트 루프에 배치하면 곧바로 실행될 겁니다.</p>
+
+<h3 id="clearTimeout_와_clearInterval의_취소기능">clearTimeout() 와 clearInterval()의 취소기능</h3>
+
+<p>clearTimeout ()과 clearInterval ()은 모두 동일한 entry를 사용하여 대상 메소드(setTimeout () 또는 setInterval ())을 취소합니다. 흥미롭게도 이는 setTimeout () 또는 setInterval ()을 지우는 데 clearTimeout ()과 clearInterval ()메소드 어느 것을 사용해도 무방합니다.</p>
+
+<p>그러나 일관성을 유지하려면 clearTimeout ()을 사용하여 setTimeout () 항목을 지우고 clearInterval ()을 사용하여 setInterval () 항목을 지우십시오. 혼란을 피하는 데 도움이됩니다.</p>
+
+<h2 id="requestAnimationFrame">requestAnimationFrame()</h2>
+
+<p>requestAnimationFrame ()은 브라우저에서 애니메이션을 효율적으로 실행하기 위해 만들어진 특수한 반복 함수입니다. 근본적으로 setInterval ()의 최신 버전입니다. 브라우저가 다음에 디스플레이를 다시 표시하기 전에 지정된 코드 블록을 실행하여 애니메이션이 실행되는 환경에 관계없이 적절한 프레임 속도로 실행될 수 있도록합니다.</p>
+
+<p>setInterval ()을 사용함에 있어 알려진 문제점을 개선하기위해 만들어졌습니다. 예를 들어 장치에 최적화 된 프레임 속도로 실행되지 않는 문제,  때로는 프레임을 빠뜨리는 문제,  탭이 활성 탭이 아니거나 애니메이션이 페이지를 벗어난 경우에도 계속 실행되는 문제 등등이다 . <a href="http://creativejs.com/resources/requestanimationframe/index.html">CreativeJS에서 이에 대해 자세히 알아보십시오.</a></p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: requestAnimationFrame() 사용에 관한 예제들은 이 코스의 여러곳에서 찾아볼 수 있습니다. <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Drawing graphics</a> 와 <a href="/en-US/docs/Learn/JavaScript/Objects/Object_building_practice">Object building practice</a> 의 예제를 찾아 보세요.</p>
+</div>
+
+<p>이 메소드는 화면을 다시 표시하기 전에 호출 할 콜백을 인수로 사용합니다. 이것이 일반적인 패턴입니다. 아래는 사용예를 보여줍니다.</p>
+
+<pre class="brush: js">function draw() {
+ // Drawing code goes here
+ requestAnimationFrame(draw);
+}
+
+draw();</pre>
+
+<p>그 발상은 애니메이션을 업데이트하는 함수 (예 : 스프라이트 이동, 스코어 업데이트, 데이터 새로 고침 등)를 정의한 후 그것을 호출하여 프로세스를 시작하는 것입니다. 함수 블록의 끝에서 매개 변수로 전달 된 함수 참조를 사용하여 requestAnimationFrame ()을 호출하면 브라우저가 다음 화면을 재표시할 때 함수를 다시 호출하도록 지시합니다. 그런 다음 requestAnimationFrame ()을 반복적으로 호출하므로 계속 실행되는 것입니다.</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: 어떤 간단한  DOM 애니메이션을 수행하려는 경우,   <a href="/en-US/docs/Web/CSS/CSS_Animations">CSS Animations</a> 은 JavaScript가 아닌 브라우저의 내부 코드로 직접 계산되므로 속도가 더 빠릅니다. 그러나 더 복잡한 작업을 수행하고 DOM 내에서 직접 액세스 할 수 없는 객체(예 :<a href="/en-US/docs/Web/API/Canvas_API">2D Canvas API</a> or <a href="/en-US/docs/Web/API/WebGL_API">WebGL</a> objects)를 포함하는 경우 대부분의 경우 requestAnimationFrame ()이 더 나은 옵션입니다. </p>
+</div>
+
+<h3 id="여러분의_애니메이션의_작동속도는_얼마나_빠른가요">여러분의 애니메이션의 작동속도는 얼마나 빠른가요?</h3>
+
+<p>부드러운 애니메이션을 구현은 직접적으로 프레임 속도에 달려 있으며, 프레임속도는 초당 프레임 (fps)으로 측정됩니다. 이 숫자가 높을수록 애니메이션이 더 매끄럽게 보입니다.</p>
+
+<p>일반적으로 화면 재생률는 60Hz이므로 웹 브라우저를 사용할 때 여러분이 설정할 수 있는 가장 빠른 프레임 속도는 초당 60 프레임 (FPS)입니다. 이 속도보다 빠르게 설정하면 과도한 연산이 실행되어 화면이 더듬거리고 띄엄띄엄 표시될 수 있다. 이런 현상을 프레임 손실 또는 쟁크라고 한다. </p>
+
+<p>재생률 60Hz의 모니터에 60FPS를 달성하려는 경우 각 프레임을 렌더링하기 위해 애니메이션 코드를 실행하려면 약 16.7ms(1000/60)가 필요합니다. 그러므로 각 애니메이션 루프를 통과 할 때마다 실행하려고 하는 코드의 양을 염두에 두어야합니다.</p>
+
+<p>requestAnimationFrame()은 불가능한 경우에도 가능한한 60FPS 값에 가까워 지려고 노력합니다. 실제로 복잡한 애니메이션을 느린 컴퓨터에서 실행하는 경우 프레임 속도가 떨어집니다. requestAnimationFrame ()은 항상 사용 가능한 것을 최대한 활용합니다.</p>
+
+<h3 id="requestAnimationFrame이_setInterval_setTimeout과_다른점은">requestAnimationFrame()이 setInterval(), setTimeout()과 다른점은?</h3>
+
+<p>requestAnimationFrame () 메소드가 이전에 살펴본 다른 메소드와 어떻게 다른지에 대해 조금 더 이야기하겠습니다. 위의 코드를 다시 살펴보면;</p>
+
+<pre class="brush: js">function draw() {
+ // Drawing code goes here
+ requestAnimationFrame(draw);
+}
+
+draw();</pre>
+
+<p>setInterval()을 사용하여 위와 같은 작업을 하는 방법을 살펴봅시다.</p>
+
+<pre class="brush: js">function draw() {
+ // Drawing code goes here
+}
+
+setInterval(draw, 17);</pre>
+
+<p>앞에서언급했듯이 requestAnimationFrame ()은 시간 간격을 지정하지 않습니다. requestAnimationFrame ()은 현재 상황에서 최대한 빠르고 원활하게 실행됩니다. 어떤 이유로 애니메이션이 화면에 표시되지 않으면 브라우저는 그 애니메이션을 실행하는 데 시간을 낭비하지 않습니다.</p>
+
+<p>반면에 setInterval ()은 특정 시간간격을 필요로 합니다. 1000 ms/60Hz 계산을 통해 최종값 16.6에 도달 한 후 반올림(17)했습니다. 이때 반올림하는 것이 좋습니다. 그 이유는 반내림(16)을하면 60fps보다 빠르게 애니메이션을 실행하려고 하게 되지만 애니메이션의 부드러움에 아무런 영향을 미치지 않기 때문입니다. 앞에서 언급했듯이 60Hz가 표준 재생률입니다.</p>
+
+<h3 id="timestamp를_포함하기">timestamp를 포함하기</h3>
+
+<p>requestAnimationFrame() 함수에 전달 된 실제 콜백에는 requestAnimationFrame()이 실행되기 시작한 이후의 시간을 나타내는 timestamp를  매개변수로 제공할 수 있습니다. 장치 속도에 관계없이 특정 시간과 일정한 속도로 작업을 수행할 수 있으므로 유용합니다. 사용하는 일반적인 패턴은 다음과 같습니다.</p>
+
+<pre class="brush: js">let startTime = null;
+
+function draw(timestamp) {
+ if(!startTime) {
+ startTime = timestamp;
+ }
+
+ currentTime = timestamp - startTime;
+
+ // Do something based on current time
+
+ requestAnimationFrame(draw);
+}
+
+draw();</pre>
+
+<h3 id="브라우저_지원">브라우저 지원</h3>
+
+<p>requestAnimationFrame()은 setInterval() / setTimeout()보다 좀 더 최신 브라우저에서 지원됩니다. 가장 흥미롭게도 Internet Explorer 10 이상에서 사용할 수 있습니다. 따라서 별도의 코드로 이전 버전의 IE를 지원해야할 필요가 없다면, requestAnimationFrame()을 사용하지 않을 이유가 없습니다.</p>
+
+<h3 id="간단한_예">간단한 예</h3>
+
+<p>지금까지 이론적으로는 충분히 살펴보았습니다. 그러면 직접 requestAnimationFrame() 예제를 작성해 봅시다. 우리는 간단한 "스피너 애니메이션"을 만들 것입니다. 여러분들이 앱 사용중 서버 과부하일 때 이것을 자주 보았을 겁니다.</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: 실제로는 CSS 애니메이션을 사용하여 이러한 종류의 간단한 애니메이션을 실행해야 합니다. 그러나 이러한 종류의 예제는 requestAnimationFrame() 사용법을 보여주는 데 매우 유용하며, 각 프레임에서 게임의 디스플레이를 업데이트하는 것과 같이 좀 더 복잡한 작업을 수행 할 때 이러한 종류의 기술을 사용하는 것이 좋습니다.</p>
+</div>
+
+<ol>
+ <li>
+ <p>먼저 HTML 템플릿을 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">여기</a>에서.가져옵니다.</p>
+ </li>
+ <li>
+ <p>&lt;body&gt;안에 빈 &lt;div&gt; 요소를 삽입합니다. 그리고  ↻캐릭터를 그 안에 추가합니다. 이 예제에서 이 원형 화살표가 회전하게됩니다.</p>
+ </li>
+ <li>
+ <p>아래 CSS를 HTML 템플릿에 여러분이 원하는 방식으로 적용하세요. 이 CSS는 페이지 배경을 빨간색으로, &lt;body&gt;의 height를 html height의 100%로 설정합니다. 그리고 &lt;div&gt;를 수직, 수평으로 &lt;body&gt; 중앙에 위치 시킵니다.</p>
+
+ <pre class="brush: css">html {
+ background-color: white;
+ height: 100%;
+}
+
+body {
+ height: inherit;
+ background-color: red;
+ margin: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+div {
+ display: inline-block;
+ font-size: 10rem;
+}</pre>
+ </li>
+ <li>
+ <p>&lt;/body&gt; 태크 위에 &lt;script&gt;를 추가하세요.</p>
+ </li>
+ <li>
+ <p>&lt;script&gt; 안에 아래 자바스크립트 코드를 추가하세요. 여기에서 &lt;div&gt;의 참조를 상수로 저장하고, rotateCount 변수를 0으로 설정하고, 나중에 requestAnimationFrame()의 시작 시간을 저장할 startTime 변수를 null로 설정하고, 그리고 requestAnimationFrame() 콜의 참조를 저장할 초기화하지 않은 rAF 변수를 선언합니다.</p>
+
+ <pre class="brush: js">const spinner = document.querySelector('div');
+let rotateCount = 0;
+let startTime = null;
+let rAF;
+</pre>
+ </li>
+ <li>
+ <p>그 아래에 draw() 함수를 추가합니다. 이 함수는 timestamp 매개변수를 포함하는 애니메이션 코드 작성에 사용됩니다.</p>
+
+ <pre class="brush: js">function draw(timestamp) {
+
+}</pre>
+ </li>
+ <li>
+ <p>draw() 함수안데 다음 코드를 추가합니다. if 조건문으로 startTime이 정의되지 않았다면 startTime을 정의합니다 (루프 반복의 첫번째에만 작동합니다).  그리고 스피너를 회전시키는 rotateCount 변수값을 설정합니다(현재 timestamp는 시작 timestamp를 3으로 나눈 것이라서 그리 빠르지 않습니다).</p>
+
+ <pre class="brush: js"> if (!startTime) {
+ startTime = timestamp;
+ }
+
+ rotateCount = (timestamp - startTime) / 3;
+</pre>
+ </li>
+ <li>
+ <p>draw() 함수 안의 이전 코드 아래에 다음 블록을 추가합니다. 이렇게하면 rotateCount 값이 359보다 큰지 확인합니다 (예 : 360, 완전한 원). 그렇다면 값을 모듈러 360 (즉, 값을 360으로 나눌 때 남은 나머지)으로 설정하여 원 애니메이션이 합리적인 낮은 값으로 중단없이 계속 될 수 있습니다. 꼭 이렇게 해야되는 것은 아니지만 "128000도" 같은 값보다는 0~359 도의 값으로 작업하는 것이 더 쉽습니다.</p>
+
+ <pre class="brush: js">if (rotateCount &gt; 359) {
+ rotateCount %= 360;
+}</pre>
+ </li>
+ <li>다음으로 아래 코드를 추가하세요. 실제 스피너를 회전시키는 코드입니다.
+ <pre class="brush: js">spinner.style.transform = 'rotate(' + rotateCount + 'deg)';</pre>
+ </li>
+ <li>
+ <p> draw() 함수 제일 아래에 다음 코드를 추가합니다. 이 코드는 모든 작업의 키 포인트입니다. draw() 함수를 매개변수로 가져오는 requestAnimationFrame() 콜을 저장하기 위해 앞에서 정의한  rAF 변수를 설정합니다. 이 코드는 애니메이션을 실행시키고, 가능한한 60fps에 근사하게 draw() 함수를 계속 실행합니다.</p>
+
+ <pre class="brush: js">rAF = requestAnimationFrame(draw);</pre>
+ </li>
+</ol>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: You can find this <a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/simple-raf-spinner.html">example live on GitHub</a> (see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/simple-raf-spinner.html">source code</a> also).</p>
+</div>
+
+<h3 id="requestAnimationFrame_call의_취소">requestAnimationFrame() call의 취소</h3>
+
+<p>cancelAnimationFrame() 메소드를 호출하여 requestAnimationFrame()을 취소할 수 있다. (접두어가 "clear"가 아니고 "cancel"임에 유의) requestAnimationFrame()에 의해서 리턴된 rAF 변수값을 전달받아 취소한다. </p>
+
+<pre class="brush: js">cancelAnimationFrame(rAF);</pre>
+
+<h3 id="Active_learning_Starting_and_stopping_our_spinner">Active learning: Starting and stopping our spinner</h3>
+
+<p>In this exercise, we'd like you to test out the <code>cancelAnimationFrame()</code> method by taking our previous example and updating it, adding an event listener to start and stop the spinner when the mouse is clicked anywhere on the page.</p>
+
+<p>Some hints:</p>
+
+<ul>
+ <li>A <code>click</code> event handler can be added to most elements, including the document <code>&lt;body&gt;</code>. It makes more sense to put it on the <code>&lt;body&gt;</code> element if you want to maximize the clickable area — the event bubbles up to its child elements.</li>
+ <li>You'll want to add a tracking variable to check whether the spinner is spinning or not, clearing the animation frame if it is, and calling it again if it isn't.</li>
+</ul>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: Try this yourself first; if you get really stuck, check out of our <a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/start-and-stop-spinner.html">live example</a> and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/start-and-stop-spinner.html">source code</a>.</p>
+</div>
+
+<h3 id="Throttling_a_requestAnimationFrame_animation">Throttling a requestAnimationFrame() animation</h3>
+
+<p>One limitation of <code>requestAnimationFrame()</code> is that you can't choose your frame rate. This isn't a problem most of the time, as generally you want your animation to run as smoothly as possible, but what about when you want to create an old school, 8-bit-style animation?</p>
+
+<p>This was a problem for example in the Monkey Island-inspired walking animation from our <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Drawing Graphics</a> article:</p>
+
+<p>{{EmbedGHLiveSample("learning-area/javascript/apis/drawing-graphics/loops_animation/7_canvas_walking_animation.html", '100%', 260)}}</p>
+
+<p>In this example we have to animate both the position of the character on the screen, and the sprite being shown. There are only 6 frames in the sprite's animation; if we showed a different sprite frame for every frame displayed on the screen by <code>requestAnimationFrame()</code>, Guybrush would move his limbs too fast and the animation would look ridiculous. We therefore throttled the rate at which the sprite cycles its frames using the following code:</p>
+
+<pre class="brush: js">if (posX % 13 === 0) {
+ if (sprite === 5) {
+ sprite = 0;
+ } else {
+ sprite++;
+ }
+}</pre>
+
+<p>So we are only cycling a sprite once every 13 animation frames. OK, so it's actually about every 6.5 frames, as we update <code>posX</code> (character's position on the screen) by two each frame:</p>
+
+<pre class="brush: js">if(posX &gt; width/2) {
+ newStartPos = -((width/2) + 102);
+ posX = Math.ceil(newStartPos / 13) * 13;
+ console.log(posX);
+} else {
+ posX += 2;
+}</pre>
+
+<p>This is the code that works out how to update the position in each animation frame.</p>
+
+<p>The method you use to throttle your animation will depend on your particular code. For example, in our spinner example we could make it appear to move slower by only increasing our <code>rotateCount</code> by one on each frame instead of two.</p>
+
+<h2 id="Active_learning_a_reaction_game">Active learning: a reaction game</h2>
+
+<p>For our final section of this article, we'll create a 2-player reaction game. Here we have two players, one of whom controls the game using the <kbd>A</kbd> key, and the other with the <kbd>L</kbd> key.</p>
+
+<p>When the <em>Start</em> button is pressed, a spinner like the one we saw earlier is displayed for a random amount of time between 5 and 10 seconds. After that time, a message will appear saying "PLAYERS GO!!" — once this happens, the first player to press their control button will win the game.</p>
+
+<p>{{EmbedGHLiveSample("learning-area/javascript/asynchronous/loops-and-intervals/reaction-game.html", '100%', 500)}}</p>
+
+<p>Let's work through this.</p>
+
+<ol>
+ <li>
+ <p>First of all, download the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/reaction-game-starter.html">starter file for the app</a> — this contains the finished HTML structure and CSS styling, giving us a game board that shows the two players' information (as seen above), but with the spinner and results paragraph displayed on top of one another. We just have to write the JavaScript code.</p>
+ </li>
+ <li>
+ <p>Inside the empty {{htmlelement("script")}} element on your page, start by adding the following lines of code that define some constants and variables we'll need in the rest of the code:</p>
+
+ <pre class="brush: js">const spinner = document.querySelector('.spinner p');
+const spinnerContainer = document.querySelector('.spinner');
+let rotateCount = 0;
+let startTime = null;
+let rAF;
+const btn = document.querySelector('button');
+const result = document.querySelector('.result');</pre>
+
+ <p>In order, these are:</p>
+
+ <ol>
+ <li>A reference to our spinner, so we can animate it.</li>
+ <li>A reference to the {{htmlelement("div")}} element that contains the spinner, used for showing and hiding it.</li>
+ <li>A rotate count — how much we want to show the spinner rotated on each frame of the animation.</li>
+ <li>A null start time — will be populated with a start time when the spinner starts spinning.</li>
+ <li>An uninitialized variable to later store the {{domxref("Window.requestAnimationFrame", "requestAnimationFrame()")}} call that animates the spinner.</li>
+ <li>A reference to the Start button.</li>
+ <li>A reference to the results paragraph.</li>
+ </ol>
+ </li>
+ <li>
+ <p>Next, below the previous lines of code, add the following function. This simply takes two numerical inputs and returns a random number between the two. We'll need this to generate a random timeout interval later on.</p>
+
+ <pre class="brush: js">function random(min,max) {
+ var num = Math.floor(Math.random()*(max-min)) + min;
+ return num;
+}</pre>
+ </li>
+ <li>
+ <p>Next add in the <code>draw()</code> function, which animates the spinner. This is very similar to the version seen in the simple spinner example we looked at earlier:</p>
+
+ <pre class="brush: js">function draw(timestamp) {
+ if(!startTime) {
+ startTime = timestamp;
+ }
+
+ rotateCount = (timestamp - startTime) / 3;
+
+ if(rotateCount &gt; 359) {
+ rotateCount %= 360;
+ }
+
+ spinner.style.transform = 'rotate(' + rotateCount + 'deg)';
+ rAF = requestAnimationFrame(draw);
+}</pre>
+ </li>
+ <li>
+ <p>Now it is time to set up the initial state of the app when the page first loads. Add the following two lines, which simply hide the results paragraph and spinner container using <code>display: none;</code>.</p>
+
+ <pre class="brush: js">result.style.display = 'none';
+spinnerContainer.style.display = 'none';</pre>
+ </li>
+ <li>
+ <p>We'll also define a <code>reset()</code> function, which sets the app back to the original state required to start the game again after it has been played. Add the following at the bottom of your code:</p>
+
+ <pre class="brush: js">function reset() {
+ btn.style.display = 'block';
+ result.textContent = '';
+ result.style.display = 'none';
+}</pre>
+ </li>
+ <li>
+ <p>OK, enough preparation.  Let's make the game playable! Add the following block to your code. The <code>start()</code> function calls <code>draw()</code> to start the spinner spinning and display it in the UI, hides the <em>Start</em> button so we can't mess up the game by starting it multiple times concurrently, and runs a <code>setTimeout()</code> call that runs a <code>setEndgame()</code> function after a random interval between 5 and 10 seconds has passed. We also add an event listener to our button to run the <code>start()</code> function when it is clicked.</p>
+
+ <pre class="brush: js">btn.addEventListener('click', start);
+
+function start() {
+ draw();
+ spinnerContainer.style.display = 'block';
+ btn.style.display = 'none';
+ setTimeout(setEndgame, random(5000,10000));
+}</pre>
+
+ <div class="blockIndicator note">
+ <p><strong>Note</strong>: You'll see that in this example we are calling <code>setTimeout()</code> without storing the return value (so not <code>let myTimeout = setTimeout(functionName, interval)</code>). This works and is fine, as long as you don't need to clear your interval/timeout at any point. If you do, you'll need to save the returned identifier.</p>
+ </div>
+
+ <p>The net result of the previous code is that when the <em>Start</em> button is pressed, the spinner is shown and the players are made to wait a random amount of time before they are then asked to press their button. This last part is handled by the <code>setEndgame()</code> function, which we should define next.</p>
+ </li>
+ <li>
+ <p>So add the following function to your code next:</p>
+
+ <pre class="brush: js">function setEndgame() {
+ cancelAnimationFrame(rAF);
+ spinnerContainer.style.display = 'none';
+ result.style.display = 'block';
+ result.textContent = 'PLAYERS GO!!';
+
+ document.addEventListener('keydown', keyHandler);
+
+ function keyHandler(e) {
+ console.log(e.key);
+ if(e.key === 'a') {
+ result.textContent = 'Player 1 won!!';
+ } else if(e.key === 'l') {
+ result.textContent = 'Player 2 won!!';
+ }
+
+ document.removeEventListener('keydown', keyHandler);
+ setTimeout(reset, 5000);
+ };
+}</pre>
+
+ <p>Stepping through this:</p>
+
+ <ol>
+ <li>First we cancel the spinner animation with {{domxref("window.cancelAnimationFrame", "cancelAnimationFrame()")}} (it is always good to clean up unneeded processes), and hide the spinner container.</li>
+ <li>Next we display the results paragraph and set its text content to "PLAYERS GO!!" to signal to the players that they can now press their button to win.</li>
+ <li>We then attach a <code><a href="/en-US/docs/Web/API/Document/keydown_event">keydown</a></code> event listener to our document — when any button is pressed down, the <code>keyHandler()</code> function is run.</li>
+ <li>Inside <code>keyHandler()</code>, we include the event object as a parameter (represented by <code>e</code>) — its {{domxref("KeyboardEvent.key", "key")}} property contains the key that was just pressed, and we can use this to respond to specific key presses with specific actions.</li>
+ <li>We first log <code>e.key</code> to the console, which is a useful way of finding out the <code>key</code> value of different keys you are pressing.</li>
+ <li>When <code>e.key</code> is "a", we display a message to say that Player 1 won, and when <code>e.key</code> is "l", we display a message to say Player 2 won. Note that this will only work with lowercase a and l — if an uppercase A or L is submitted (the key plus <kbd>Shift</kbd>), it is counted as a different key.</li>
+ <li>Regardless of which one of the player control keys was pressed, we remove the <code>keydown</code> event listener using {{domxref("EventTarget.removeEventListener", "removeEventListener()")}} so that once the winning press has happened, no more keyboard input is possible to mess up the final game result. We also use <code>setTimeout()</code> to call <code>reset()</code> after 5 seconds — as we explained earlier, this function resets the game back to its original state so that a new game can be started.</li>
+ </ol>
+ </li>
+</ol>
+
+<p>That's it, you're all done.</p>
+
+<div class="blockIndicator note">
+<p><strong>Note</strong>: If you get stuck, check out <a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/reaction-game.html">our version of the reaction game</a> (see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/reaction-game.html">source code</a> also).</p>
+</div>
+
+<h2 id="Conclusion">Conclusion</h2>
+
+<p>So that's it — all the essentials of async loops and intervals covered in one article. You'll find these methods useful in a lot of situations, but take care not to overuse them — since these still run on the main thread, heavy and intensive callbacks (especially those that manipulate the DOM) can really slow down a page if you're not careful.</p>
+
+<p>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Introducing", "Learn/JavaScript/Asynchronous/Promises", "Learn/JavaScript/Asynchronous")}}</p>
+
+<h2 id="In_this_module">In this module</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">General asynchronous programming concepts</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Introducing asynchronous JavaScript</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">Cooperative asynchronous JavaScript: Timeouts and intervals</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Graceful asynchronous programming with Promises</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">Making asynchronous programming easier with async and await</a></li>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">Choosing the right approach</a></li>
+</ul>