aboutsummaryrefslogtreecommitdiff
path: root/files/zh-tw/learn
diff options
context:
space:
mode:
authorian7525 <ian7525@gmail.com>2021-05-01 10:31:33 +0800
committerIrvin <irvinfly@gmail.com>2021-05-01 17:17:05 +0800
commit03e2f89170237b85d52ebc867dd3b812a3661d6b (patch)
tree40aaea97f1d7433c58142b09169b8b2b22c23fc1 /files/zh-tw/learn
parent09ebefcc09edd4fe62a06b1a1fa1058785abcfdb (diff)
downloadtranslated-content-03e2f89170237b85d52ebc867dd3b812a3661d6b.tar.gz
translated-content-03e2f89170237b85d52ebc867dd3b812a3661d6b.tar.bz2
translated-content-03e2f89170237b85d52ebc867dd3b812a3661d6b.zip
Add /learn/javascript/asynchronous/ folder, zh-TW
Diffstat (limited to 'files/zh-tw/learn')
-rw-r--r--files/zh-tw/learn/javascript/asynchronous/async_await/index.html435
-rw-r--r--files/zh-tw/learn/javascript/asynchronous/choosing_the_right_approach/index.html536
-rw-r--r--files/zh-tw/learn/javascript/asynchronous/concepts/beachball.jpgbin0 -> 7495 bytes
-rw-r--r--files/zh-tw/learn/javascript/asynchronous/concepts/index.html163
-rw-r--r--files/zh-tw/learn/javascript/asynchronous/index.html66
-rw-r--r--files/zh-tw/learn/javascript/asynchronous/introducing/index.html287
-rw-r--r--files/zh-tw/learn/javascript/asynchronous/promises/index.html600
-rw-r--r--files/zh-tw/learn/javascript/asynchronous/timeouts_and_intervals/index.html646
8 files changed, 2733 insertions, 0 deletions
diff --git a/files/zh-tw/learn/javascript/asynchronous/async_await/index.html b/files/zh-tw/learn/javascript/asynchronous/async_await/index.html
new file mode 100644
index 0000000000..3c594daf2a
--- /dev/null
+++ b/files/zh-tw/learn/javascript/asynchronous/async_await/index.html
@@ -0,0 +1,435 @@
+---
+title: 利用 async 及 await 讓非同步程式設計變得更容易
+slug: Learn/JavaScript/Asynchronous/Async_await
+tags:
+ - Beginner
+ - CodingScripting
+ - Guide
+ - JavaScript
+ - Learn
+ - Promises
+ - async
+ - asynchronous
+ - await
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Promises", "Learn/JavaScript/Asynchronous/Choosing_the_right_approach", "Learn/JavaScript/Asynchronous")}}</div>
+
+<p class="summary">More recent additions to the JavaScript language are <a href="/en-US/docs/Web/JavaScript/Reference/Statements/async_function">async functions</a> and the <code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/await">await</a></code> keyword, part of the so-called ECMAScript 2017 JavaScript edition (see <a href="/en-US/docs/Web/JavaScript/New_in_JavaScript/ECMAScript_Next_support_in_Mozilla">ECMAScript Next support in Mozilla</a>). These features basically act as syntactic sugar on top of promises, making asynchronous code easier to write and to read afterwards. They make async code look more like old-school synchronous code, so they're well worth learning. This article gives you what you need to know.</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>There are two parts to using async/await in your code.</p>
+
+<h3 id="The_async_keyword">The async keyword</h3>
+
+<p>First of all we have the <code>async</code> keyword, which you put in front of a function declaration to turn it into an <a href="/en-US/docs/Web/JavaScript/Reference/Statements/async_function">async function</a>. An async function is a function that knows how to expect the possibility of the <code>await</code> keyword being used to invoke asynchronous code.</p>
+
+<p>Try typing the following lines into your browser's JS console:</p>
+
+<pre class="brush: js">function hello() { return "Hello" };
+hello();</pre>
+
+<p>The function returns "Hello" — nothing special, right?</p>
+
+<p>But what if we turn this into an async function? Try the following:</p>
+
+<pre class="brush: js">async function hello() { return "Hello" };
+hello();</pre>
+
+<p>Ah. Invoking the function now returns a promise. This is one of the traits of async functions — their return values are guaranteed to be converted to promises.</p>
+
+<p>You can also create an <a href="/en-US/docs/Web/JavaScript/Reference/Operators/async_function">async function expression</a>, like so:</p>
+
+<pre class="brush: js">let hello = async function() { return "Hello" };
+hello();</pre>
+
+<p>And you can use arrow functions:</p>
+
+<pre class="brush: js">let hello = async () =&gt; { return "Hello" };</pre>
+
+<p>These all do basically the same thing.</p>
+
+<p>To actually consume the value returned when the promise fulfills, since it is returning a promise, we could use a <code>.then()</code> block:</p>
+
+<pre class="brush: js">hello().then((value) =&gt; console.log(value))</pre>
+
+<p>or even just shorthand such as</p>
+
+<pre class="brush: js">hello().then(console.log)</pre>
+
+<p>Like we saw in the last article.</p>
+
+<p>So the <code>async</code> keyword is added to functions to tell them to return a promise rather than directly returning the value.</p>
+
+<h3 id="The_await_keyword">The await keyword</h3>
+
+<p>The advantage of an async function only becomes apparent when you combine it with the <a href="/en-US/docs/Web/JavaScript/Reference/Operators/await">await</a> keyword. <code>await</code> only works inside async functions within regular JavaScript code, however it can be used on its own with <a href="/en-US/docs/Web/JavaScript/Guide/Modules">JavaScript modules.</a></p>
+
+<p><code>await</code> can be put in front of any async promise-based function to pause your code on that line until the promise fulfills, then return the resulting value.</p>
+
+<p>You can use <code>await</code> when calling any function that returns a Promise, including web API functions.</p>
+
+<p>Here is a trivial example:</p>
+
+<pre class="brush: js">async function hello() {
+ return greeting = await Promise.resolve("Hello");
+};
+
+hello().then(alert);</pre>
+
+<p>Of course, the above example is not very useful, although it does serve to illustrate the syntax. Let's move on and look at a real example.</p>
+
+<h2 id="Rewriting_promise_code_with_asyncawait">Rewriting promise code with async/await</h2>
+
+<p>Let's look back at a simple fetch example that we saw in the previous article:</p>
+
+<pre class="brush: js">fetch('coffee.jpg')
+.then(response =&gt; {
+  if (!response.ok) {
+    throw new Error(`HTTP error! status: ${response.status}`);
+  }
+  return 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>By now, you should have a reasonable understanding of promises and how they work, but let's convert this to use async/await to see how much simpler it makes things:</p>
+
+<pre class="brush: js">async function myFetch() {
+ let response = await fetch('coffee.jpg');
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ 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>It makes code much simpler and easier to understand — no more <code>.then()</code> blocks everywhere!</p>
+
+<p>Since an <code>async</code> keyword turns a function into a promise, you could refactor your code to use a hybrid approach of promises and await, bringing the second half of the function out into a new block to make it more flexible:</p>
+
+<pre class="brush: js">async function myFetch() {
+ let response = await fetch('coffee.jpg');
+ if (!response.ok) {
+    throw new Error(`HTTP error! status: ${response.status}`);
+  }
+  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>You can try typing in the example yourself, or running our <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>You'll note that we've wrapped the code inside a function, and we've included the <code>async</code> keyword before the <code>function</code> keyword. This is necessary — you have to create an async function to define a block of code in which you'll run your async code; as we said earlier, <code>await</code> only works inside of async functions.</p>
+
+<p>Inside the <code>myFetch()</code> function definition you can see that the code closely resembles the previous promise version, but there are some differences. Instead of needing to chain a <code>.then()</code> block on to the end of each promise-based method, you just need to add an <code>await</code> keyword before the method call, and then assign the result to a variable. The <code>await</code> keyword causes the JavaScript runtime to pause your code on this line, not allowing further code to execute in the meantime until the async function call has returned its result — very useful if subsequent code relies on that result!</p>
+
+<p>Once that's complete, your code continues to execute starting on the next line. For example:</p>
+
+<pre class="brush: js">let response = await fetch('coffee.jpg');</pre>
+
+<p>The response returned by the fulfilled <code>fetch()</code> promise is assigned to the <code>response</code> variable when that response becomes available, and the parser pauses on this line until that occurs. Once the response is available, the parser moves to the next line, which creates a <code><a href="/en-US/docs/Web/API/Blob">Blob</a></code> out of it. This line also invokes an async promise-based method, so we use <code>await</code> here as well. When the result of operation returns, we return it out of the <code>myFetch()</code> function.</p>
+
+<p>This means that when we call the <code>myFetch()</code> function, it returns a promise, so we can chain a <code>.then()</code> onto the end of it inside which we handle displaying the blob onscreen.</p>
+
+<p>You are probably already thinking "this is really cool!", and you are right — fewer <code>.then()</code> blocks to wrap around code, and it mostly just looks like synchronous code, so it is really intuitive.</p>
+
+<h3 id="Adding_error_handling">Adding error handling</h3>
+
+<p>And if you want to add error handling, you've got a couple of options.</p>
+
+<p>You can use a synchronous <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/try...catch">try...catch</a></code> structure with <code>async</code>/<code>await</code>. This example expands on the first version of the code we showed above:</p>
+
+<pre class="brush: js">async function myFetch() {
+ try {
+ let response = await fetch('coffee.jpg');
+
+ if (!response.ok) {
+  throw new Error(`HTTP error! status: ${response.status}`);
+ }
+  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>The <code>catch() {}</code> block is passed an error object, which we've called <code>e</code>; we can now log that to the console, and it will give us a detailed error message showing where in the code the error was thrown.</p>
+
+<p>If you wanted to use the second (refactored) version of the code that we showed above, you would be better off just continuing the hybrid approach and chaining a <code>.catch()</code> block onto the end of the <code>.then()</code> call, like this:</p>
+
+<pre class="brush: js">async function myFetch() {
+ let response = await fetch('coffee.jpg');
+ if (!response.ok) {
+  throw new Error(`HTTP error! status: ${response.status}`);
+ }
+  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>This is because the <code>.catch()</code> block will catch errors occurring in both the async function call and the promise chain. If you used the <code>try</code>/<code>catch</code> block here, you might still get unhandled errors in the <code>myFetch()</code> function when it's called.</p>
+
+<p>You can find both of these examples on 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 is built on top of <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">promises</a>, so it's compatible with all the features offered by promises. This includes <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all">Promise.all()</a></code> — you can quite happily await a <code>Promise.all()</code> call to get all the results returned into a variable in a way that looks like simple synchronous code. Again, let's return to <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>. Keep it open in a separate tab so you can compare and contrast with the new version shown below.</p>
+
+<p>Converting this to async/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>), this now looks like so:</p>
+
+<pre class="brush: js">async function fetchAndDecode(url, type) {
+ let response = await fetch(url);
+
+ let content;
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+ 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>You'll see that the <code>fetchAndDecode()</code> function has been converted easily into an async function with just a few changes. See the <code>Promise.all()</code> line:</p>
+
+<pre class="brush: js">let values = await Promise.all([coffee, tea, description]);</pre>
+
+<p>By using <code>await</code> here we are able to get all the results of the three promises returned into the <code>values</code> array, when they are all available, in a way that looks very much like sync code. We've had to wrap all the code in a new async function, <code>displayContent()</code>, and we've not reduced the code by a lot of lines, but being able to move the bulk of the code out of the <code>.then()</code> block provides a nice, useful simplification, leaving us with a much more readable program.</p>
+
+<p>For error handling, we've included a <code>.catch()</code> block on our <code>displayContent()</code> call; this will handle errors occurring in both functions.</p>
+
+<div class="notecard 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 is really useful to know about, but there are a couple of downsides to consider.</p>
+
+<p>Async/await makes your code look synchronous, and in a way it makes it behave more synchronously. The <code>await</code> keyword blocks execution of all the code that follows it until the promise fulfills, exactly as it would with a synchronous operation. It does allow other tasks to continue to run in the meantime, but the awaited code is blocked.</p>
+
+<pre class="brush: js">async function makeResult(items) {
+ let newArr = [];
+ for(let i=0; i &lt; items.length; i++) {
+ newArr.push('word_'+i);
+ }
+ return newArr;
+}
+
+async function getResult() {
+ let result = await makeResult(items); // Blocked on this line
+ useThatResult(result); // Will not be executed before makeResult() is done
+}
+
+</pre>
+
+<p>This means that your code could be slowed down by a significant number of awaited promises happening straight after one another. Each <code>await</code> will wait for the previous one to finish, whereas actually what you want is for the promises to begin processing simultaneously, like they would do if we weren't using async/await.</p>
+
+<p>There is a pattern that can mitigate this problem — setting off all the promise processes by storing the <code>Promise</code> objects in variables, and then awaiting them all afterwards. Let's have a look at some examples that prove the concept.</p>
+
+<p>We've got two examples available — <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>) and <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>). Both of them start off with a custom promise function that fakes an async process with a <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout">setTimeout()</a></code> call:</p>
+
+<pre class="brush: js">function timeoutPromise(interval) {
+ return new Promise((resolve, reject) =&gt; {
+ setTimeout(function(){
+ resolve("done");
+ }, interval);
+ });
+};</pre>
+
+<p>Then each one includes a <code>timeTest()</code> async function that awaits three <code>timeoutPromise()</code> calls:</p>
+
+<pre class="brush: js">async function timeTest() {
+ ...
+}</pre>
+
+<p>Each one ends by recording a start time, seeing how long the <code>timeTest()</code> promise takes to fulfill, then recording an end time and reporting how long the operation took in total:</p>
+
+<pre class="brush: js">let startTime = Date.now();
+timeTest().then(() =&gt; {
+ let finishTime = Date.now();
+ let timeTaken = finishTime - startTime;
+ alert("Time taken in milliseconds: " + timeTaken);
+})</pre>
+
+<p>It is the <code>timeTest()</code> function that differs in each case.</p>
+
+<p>In the <code>slow-async-await.html</code> example, <code>timeTest()</code> looks like this:</p>
+
+<pre class="brush: js">async function timeTest() {
+ await timeoutPromise(3000);
+ await timeoutPromise(3000);
+ await timeoutPromise(3000);
+}</pre>
+
+<p>Here we await all three <code>timeoutPromise()</code> calls directly, making each one alert for 3 seconds. Each subsequent one is forced to wait until the last one finished — if you run the first example, you'll see the alert box reporting a total run time of around 9 seconds.</p>
+
+<p>In the <code>fast-async-await.html</code> example, <code>timeTest()</code> looks like this:</p>
+
+<pre class="brush: js">async function timeTest() {
+ const timeoutPromise1 = timeoutPromise(3000);
+ const timeoutPromise2 = timeoutPromise(3000);
+ const timeoutPromise3 = timeoutPromise(3000);
+
+ await timeoutPromise1;
+ await timeoutPromise2;
+ await timeoutPromise3;
+}</pre>
+
+<p>Here we store the three <code>Promise</code> objects in variables, which has the effect of setting off their associated processes all running simultaneously.</p>
+
+<p>Next, we await their results — because the promises all started processing at essentially the same time, the promises will all fulfill at the same time; when you run the second example, you'll see the alert box reporting a total run time of just over 3 seconds!</p>
+
+<p>You'll have to test your code carefully, and bear this in mind if performance starts to suffer.</p>
+
+<p>Another minor inconvenience is that you have to wrap your awaited promises inside an async function.</p>
+
+<h2 id="Asyncawait_class_methods">Async/await class methods</h2>
+
+<p>As a final note before we move on, you can even add <code>async</code> in front of class/object methods to make them return promises, and <code>await</code> promises inside them. Take a look at the <a href="/en-US/docs/Learn/JavaScript/Objects/Inheritance#ecmascript_2015_classes">ES class code we saw in our object-oriented JavaScript article</a>, and then look at our modified version with an <code>async</code> method:</p>
+
+<pre class="brush: js">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>The first class method could now be used something like this:</p>
+
+<pre class="brush: js">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/zh-tw/learn/javascript/asynchronous/choosing_the_right_approach/index.html b/files/zh-tw/learn/javascript/asynchronous/choosing_the_right_approach/index.html
new file mode 100644
index 0000000000..6099d470fa
--- /dev/null
+++ b/files/zh-tw/learn/javascript/asynchronous/choosing_the_right_approach/index.html
@@ -0,0 +1,536 @@
+---
+title: 選擇正確的方法
+slug: Learn/JavaScript/Asynchronous/Choosing_the_right_approach
+tags:
+ - Beginner
+ - Intervals
+ - JavaScript
+ - Learn
+ - Optimize
+ - Promises
+ - async
+ - asynchronous
+ - await
+ - requestAnimationFrame
+ - setInterval
+ - setTimeout
+ - timeouts
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenu("Learn/JavaScript/Asynchronous/Async_await", "Learn/JavaScript/Asynchronous")}}</div>
+
+<p>在結束本單元前,我們將會從先前所討論過的不同程式技巧和功能,幫助您考量在甚麼情況下應該使用哪一個,並適當的提供一些有關常見的陷阱的建議及提醒。</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 be able to make a sound choice of when to use different asynchronous programming techniques.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Asynchronous_callbacks">Asynchronous callbacks</h2>
+
+<p>Generally found in old-style APIs, involves a function being passed into another function as a parameter, which is then invoked when an asynchronous operation has been completed, so that the callback can in turn do something with the result. This is the precursor to promises; it's not as efficient or flexible. Use only when necessary.</p>
+
+<table class="standard-table">
+ <caption>Useful for...</caption>
+ <thead>
+ <tr>
+ <th scope="col">Single delayed operation</th>
+ <th scope="col">Repeating operation</th>
+ <th scope="col">Multiple sequential operations</th>
+ <th scope="col">Multiple simultaneous operations</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>No</td>
+ <td>Yes (recursive callbacks)</td>
+ <td>Yes (nested callbacks)</td>
+ <td>No</td>
+ </tr>
+ </tbody>
+</table>
+
+<h3 id="Code_example">Code example</h3>
+
+<p>An example that loads a resource via the <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>):</p>
+
+<pre class="brush: js">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>
+
+<h3 id="Pitfalls">Pitfalls</h3>
+
+<ul>
+ <li>Nested callbacks can be cumbersome and hard to read (i.e. "callback hell").</li>
+ <li>Failure callbacks need to be called once for each level of nesting, whereas with promises you can just use a single <code>.catch()</code> block to handle the errors for the entire chain.</li>
+ <li>Async callbacks just aren't very graceful.</li>
+ <li>Promise callbacks are always called in the strict order they are placed in the event queue; async callbacks aren't.</li>
+ <li>Async callbacks lose full control of how the function will be executed when passed to a third-party library.</li>
+</ul>
+
+<h3 id="Browser_compatibility">Browser compatibility</h3>
+
+<p>Really good general support, although the exact support for callbacks in APIs depends on the particular API. Refer to the reference documentation for the API you're using for more specific support info.</p>
+
+<h3 id="Further_information">Further information</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Introducing asynchronous JavaScript</a>, in particular <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing#async_callbacks">Async callbacks</a></li>
+</ul>
+
+<h2 id="setTimeout">setTimeout()</h2>
+
+<p><code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout">setTimeout()</a></code> is a method that allows you to run a function after an arbitrary amount of time has passed.</p>
+
+<table class="standard-table">
+ <caption>Useful for...</caption>
+ <thead>
+ <tr>
+ <th scope="col">Single delayed operation</th>
+ <th scope="col">Repeating operation</th>
+ <th scope="col">Multiple sequential operations</th>
+ <th scope="col">Multiple simultaneous operations</th>
+ </tr>
+ <tr>
+ <td>Yes</td>
+ <td>Yes (recursive timeouts)</td>
+ <td>Yes (nested timeouts)</td>
+ <td>No</td>
+ </tr>
+ </thead>
+</table>
+
+<h3 id="Code_example_2">Code example</h3>
+
+<p>Here the browser will wait two seconds before executing the anonymous function, then will display the alert message (<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>
+
+<h3 id="Pitfalls_2">Pitfalls</h3>
+
+<p>You can use recursive <code>setTimeout()</code> calls to run a function repeatedly in a similar fashion to <code>setInterval()</code>, using code like this:</p>
+
+<pre class="brush: js">let i = 1;
+setTimeout(function run() {
+ console.log(i);
+ i++;
+
+ setTimeout(run, 100);
+}, 100);</pre>
+
+<p>There is a difference between recursive <code>setTimeout()</code> and <code>setInterval()</code>:</p>
+
+<ul>
+ <li>Recursive <code>setTimeout()</code> guarantees at least the specified amount of time (100ms in this example) will elapse between the executions; the code will run and then wait 100 milliseconds before it runs again. The interval will be the same regardless of how long the code takes to run.</li>
+ <li>With <code>setInterval()</code>, the interval we choose <em>includes</em> the time taken to execute the code we want to run in. Let's say that the code takes 40 milliseconds to run — the interval then ends up being only 60 milliseconds.</li>
+</ul>
+
+<p>When your code has the potential to take longer to run than the time interval you’ve assigned, it’s better to use recursive <code>setTimeout()</code> — this will keep the time interval constant between executions regardless of how long the code takes to execute, and you won't get errors.</p>
+
+<h3 id="Browser_compatibility_2">Browser compatibility</h3>
+
+<p>{{Compat("api.WindowOrWorkerGlobalScope.setTimeout")}}</p>
+
+<h3 id="Further_information_2">Further information</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">Cooperative asynchronous JavaScript: Timeouts and intervals</a>, in particular <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals#settimeout()">setTimeout()</a></li>
+ <li><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout">setTimeout() reference</a></li>
+</ul>
+
+<h2 id="setInterval">setInterval()</h2>
+
+<p><code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval">setInterval()</a></code> is a method that allows you to run a function repeatedly with a set interval of time between each execution. Not as efficient as <code><a href="/en-US/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame()</a></code>, but allows you to choose a running rate/frame rate.</p>
+
+<table class="standard-table">
+ <caption>Useful for...</caption>
+ <thead>
+ <tr>
+ <th scope="col">Single delayed operation</th>
+ <th scope="col">Repeating operation</th>
+ <th scope="col">Multiple sequential operations</th>
+ <th scope="col">Multiple simultaneous operations</th>
+ </tr>
+ <tr>
+ <td>No</td>
+ <td>Yes</td>
+ <td>No (unless they are the same)</td>
+ <td>No</td>
+ </tr>
+ </thead>
+</table>
+
+<h3 id="Code_example_3">Code example</h3>
+
+<p>The following function creates a new <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date">Date()</a></code> object, extracts a time string out of it using <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleTimeString">toLocaleTimeString()</a></code>, and then displays it in the UI. We then run it once per second using <code>setInterval()</code>, creating the effect of a digital clock that updates once per second (<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>
+
+<h3 id="Pitfalls_3">Pitfalls</h3>
+
+<ul>
+ <li>The frame rate isn't optimized for the system the animation is running on, and can be somewhat inefficient. Unless you need to choose a specific (slower) framerate, it is generally better to use <code>requestAnimationFrame()</code>.</li>
+</ul>
+
+<h3 id="Browser_compatibility_3">Browser compatibility</h3>
+
+<p>{{Compat("api.WindowOrWorkerGlobalScope.setInterval")}}</p>
+
+<h3 id="Further_information_3">Further information</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">Cooperative asynchronous JavaScript: Timeouts and intervals</a>, in particular <a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval">setInterval()</a></li>
+ <li><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval">setInterval() reference</a></li>
+</ul>
+
+<h2 id="requestAnimationFrame">requestAnimationFrame()</h2>
+
+<p><code><a href="/en-US/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame()</a></code> is a method that allows you to run a function repeatedly, and efficiently, at the best framerate available given the current browser/system. You should, if at all possible, use this instead of <code>setInterval()</code>/recursive <code>setTimeout()</code>, unless you need a specific framerate.</p>
+
+<table class="standard-table">
+ <caption>Useful for...</caption>
+ <thead>
+ <tr>
+ <th scope="col">Single delayed operation</th>
+ <th scope="col">Repeating operation</th>
+ <th scope="col">Multiple sequential operations</th>
+ <th scope="col">Multiple simultaneous operations</th>
+ </tr>
+ <tr>
+ <td>No</td>
+ <td>Yes</td>
+ <td>No (unless it is the same one)</td>
+ <td>No</td>
+ </tr>
+ </thead>
+</table>
+
+<h3 id="Code_example_4">Code example</h3>
+
+<p>A simple animated spinner; 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>
+
+<pre class="brush: js">const spinner = document.querySelector('div');
+let rotateCount = 0;
+let startTime = null;
+let rAF;
+
+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);
+}
+
+draw();</pre>
+
+<h3 id="Pitfalls_4">Pitfalls</h3>
+
+<ul>
+ <li>You can't choose a specific framerate with <code>requestAnimationFrame()</code>. If you need to run your animation at a slower framerate, you'll need to use <code>setInterval()</code> or recursive <code>setTimeout()</code>.</li>
+</ul>
+
+<h3 id="Browser_compatibility_4">Browser compatibility</h3>
+
+<p>{{Compat("api.Window.requestAnimationFrame")}}</p>
+
+<h3 id="Further_information_4">Further information</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">Cooperative asynchronous JavaScript: Timeouts and intervals</a>, in particular <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals#requestanimationframe()">requestAnimationFrame()</a></li>
+ <li><a href="/en-US/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame() reference</a></li>
+</ul>
+
+<h2 id="Promises">Promises</h2>
+
+<p><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a> are a JavaScript feature that allows you to run asynchronous operations and wait until it is definitely complete before running another operation based on its result. Promises are the backbone of modern asynchronous JavaScript.</p>
+
+<table class="standard-table">
+ <caption>Useful for...</caption>
+ <thead>
+ <tr>
+ <th scope="col">Single delayed operation</th>
+ <th scope="col">Repeating operation</th>
+ <th scope="col">Multiple sequential operations</th>
+ <th scope="col">Multiple simultaneous operations</th>
+ </tr>
+ <tr>
+ <td>No</td>
+ <td>No</td>
+ <td>Yes</td>
+ <td>See <code>Promise.all()</code>, below</td>
+ </tr>
+ </thead>
+</table>
+
+<h3 id="Code_example_5">Code example</h3>
+
+<p>The following code fetches an image from the server and displays it inside an {{htmlelement("img")}} element; <a href="https://mdn.github.io/learning-area/javascript/asynchronous/promises/simple-fetch-chained.html">see it live also</a>, and see also <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/simple-fetch-chained.html">the source code</a>:</p>
+
+<pre class="brush: js">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>
+
+<h3 id="Pitfalls_5">Pitfalls</h3>
+
+<p>Promise chains can be complex and hard to parse. If you nest a number of promises, you can end up with similar troubles to callback hell. For example:</p>
+
+<pre class="brush: js">remotedb.allDocs({
+ include_docs: true,
+ attachments: true
+}).then(function (result) {
+ let docs = result.rows;
+ docs.forEach(function(element) {
+ localdb.put(element.doc).then(function(response) {
+ alert("Pulled doc with id " + element.doc._id + " and added to local db.");
+ }).catch(function (err) {
+ if (err.name == 'conflict') {
+ localdb.get(element.doc._id).then(function (resp) {
+ localdb.remove(resp._id, resp._rev).then(function (resp) {
+// et cetera...</pre>
+
+<p>It is better to use the chaining power of promises to go with a flatter, easier to parse structure:</p>
+
+<pre class="brush: js">remotedb.allDocs(...).then(function (resultOfAllDocs) {
+ return localdb.put(...);
+}).then(function (resultOfPut) {
+ return localdb.get(...);
+}).then(function (resultOfGet) {
+ return localdb.put(...);
+}).catch(function (err) {
+ console.log(err);
+});</pre>
+
+<p>or even:</p>
+
+<pre class="brush: js">remotedb.allDocs(...)
+.then(resultOfAllDocs =&gt; {
+ return localdb.put(...);
+})
+.then(resultOfPut =&gt; {
+ return localdb.get(...);
+})
+.then(resultOfGet =&gt; {
+ return localdb.put(...);
+})
+.catch(err =&gt; console.log(err));</pre>
+
+<p>That covers a lot of the basics. For a much more complete treatment, see the excellent <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.</p>
+
+<h3 id="Browser_compatibility_5">Browser compatibility</h3>
+
+<p>{{Compat("javascript.builtins.Promise")}}</p>
+
+<h3 id="Further_information_5">Further information</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Graceful asynchronous programming with Promises</a></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Guide/Using_promises">Using promises</a></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise reference</a></li>
+</ul>
+
+<h2 id="Promise.all">Promise.all()</h2>
+
+<p>A JavaScript feature that allows you to wait for multiple promises to complete before then running a further operation based on the results of all the other promises.</p>
+
+<table class="standard-table">
+ <caption>Useful for...</caption>
+ <thead>
+ <tr>
+ <th scope="col">Single delayed operation</th>
+ <th scope="col">Repeating operation</th>
+ <th scope="col">Multiple sequential operations</th>
+ <th scope="col">Multiple simultaneous operations</th>
+ </tr>
+ <tr>
+ <td>No</td>
+ <td>No</td>
+ <td>No</td>
+ <td>Yes</td>
+ </tr>
+ </thead>
+</table>
+
+<h3 id="Code_example_6">Code example</h3>
+
+<p>The following example fetches several resources from the server, and uses <code>Promise.all()</code> to wait for all of them to be available before then displaying all of them — <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>
+
+<pre class="brush: js">function fetchAndDecode(url, type) {
+ // Returning the top level promise, so the result of the entire chain is returned out of the function
+ return fetch(url).then(response =&gt; {
+ // Depending on what type of file is being fetched, use the relevant function to decode its contents
+ 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);
+ });
+}
+
+// Call the fetchAndDecode() method to fetch the images and the text, and store their promises in variables
+let coffee = fetchAndDecode('coffee.jpg', 'blob');
+let tea = fetchAndDecode('tea.jpg', 'blob');
+let description = fetchAndDecode('description.txt', 'text');
+
+// Use Promise.all() to run code only when all three function calls have resolved
+Promise.all([coffee, tea, description]).then(values =&gt; {
+ 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>
+
+<h3 id="Pitfalls_6">Pitfalls</h3>
+
+<ul>
+ <li>If a <code>Promise.all()</code> rejects, then one or more of the promises you are feeding into it inside its array parameter must be rejecting, or might not be returning promises at all. You need to check each one to see what they returned. </li>
+</ul>
+
+<h3 id="Browser_compatibility_6">Browser compatibility</h3>
+
+<p>{{Compat("javascript.builtins.Promise.all")}}</p>
+
+<h3 id="Further_information_6">Further information</h3>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises#running_code_in_response_to_multiple_promises_fulfilling">Running code in response to multiple promises fulfilling</a></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all">Promise.all() reference</a></li>
+</ul>
+
+<h2 id="Asyncawait">Async/await</h2>
+
+<p>Syntactic sugar built on top of promises that allows you to run asynchronous operations using syntax that's more like writing synchronous callback code.</p>
+
+<table class="standard-table">
+ <caption>Useful for...</caption>
+ <thead>
+ <tr>
+ <th scope="col">Single delayed operation</th>
+ <th scope="col">Repeating operation</th>
+ <th scope="col">Multiple sequential operations</th>
+ <th scope="col">Multiple simultaneous operations</th>
+ </tr>
+ <tr>
+ <td>No</td>
+ <td>No</td>
+ <td>Yes</td>
+ <td>Yes (in combination with <code>Promise.all()</code>)</td>
+ </tr>
+ </thead>
+</table>
+
+<h3 id="Code_example_7">Code example</h3>
+
+<p>The following example is a refactor of the simple promise example we saw earlier that fetches and displays an image, written using async/await (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/simple-refactored-fetch.html">see it live</a>, and see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/simple-refactored-fetch.html">source code</a>):</p>
+
+<pre class="brush: js">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();</pre>
+
+<h3 id="Pitfalls_7">Pitfalls</h3>
+
+<ul>
+ <li>You can't use the <code>await</code> operator inside a non-<code>async</code> function, or in the top level context of your code. This can sometimes result in an extra function wrapper needing to be created, which can be slightly frustrating in some circumstances. But it is worth it most of the time.</li>
+ <li>Browser support for async/await is not as good as that for promises. 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.</li>
+</ul>
+
+<h3 id="Browser_compatibility_7">Browser compatibility</h3>
+
+<p>{{Compat("javascript.statements.async_function")}}</p>
+
+<h3 id="Further_information_7">Further information</h3>
+
+<ul>
+ <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/Web/JavaScript/Reference/Statements/async_function">Async function reference</a></li>
+ <li><a href="/en-US/docs/Web/JavaScript/Reference/Operators/await">Await operator reference</a></li>
+</ul>
+
+<p>{{PreviousMenu("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/zh-tw/learn/javascript/asynchronous/concepts/beachball.jpg b/files/zh-tw/learn/javascript/asynchronous/concepts/beachball.jpg
new file mode 100644
index 0000000000..e116b4e8ea
--- /dev/null
+++ b/files/zh-tw/learn/javascript/asynchronous/concepts/beachball.jpg
Binary files differ
diff --git a/files/zh-tw/learn/javascript/asynchronous/concepts/index.html b/files/zh-tw/learn/javascript/asynchronous/concepts/index.html
new file mode 100644
index 0000000000..067ebfdf54
--- /dev/null
+++ b/files/zh-tw/learn/javascript/asynchronous/concepts/index.html
@@ -0,0 +1,163 @@
+---
+title: 非同步程式設計通用概念
+slug: Learn/JavaScript/Asynchronous/Concepts
+tags:
+ - JavaScript
+ - Learn
+ - Promises
+ - Threads
+ - asynchronous
+ - blocking
+---
+<div>{{LearnSidebar}}{{NextMenu("Learn/JavaScript/Asynchronous/Introducing", "Learn/JavaScript/Asynchronous")}}</div>
+
+<p>在本篇文章我們會介紹一些關於非同步程式設計的重要觀念,以及在網頁瀏覽器和 JavaScript 中的行為。在閱讀其他文章之前您應該先具備這些觀念。</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 the basic concepts behind asynchronous programming, and how they manifest in web browsers and JavaScript.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Asynchronous">Asynchronous?</h2>
+
+<p>Normally, a given program's code runs straight along, with only one thing happening at once. If a function relies on the result of another function, it has to wait for the other function to finish and return, and until that happens, the entire program is essentially stopped from the perspective of the user.</p>
+
+<p>Mac users, for example, sometimes experience this as the spinning rainbow-colored cursor (or "beachball" as it is often called). This cursor is how the operating system says "the current program you're using has had to stop and wait for something to finish up, and it's taking so long that I was worried you'd wonder what was going on."</p>
+
+<p><img alt="Multi-colored macOS beachball busy spinner" src="beachball.jpg" style="display: block; float: left; margin: 0px 30px 0px 0px;"></p>
+
+<p>This is a frustrating experience and isn't a good use of computer processing power — especially in an era in which computers have multiple processor cores available. There's no sense sitting there waiting for something when you could let the other task chug along on another processor core and let you know when it's done. This lets you get other work done in the meantime, which is the basis of <strong>asynchronous programming</strong>. It is up to the programming environment you are using (web browsers, in the case of web development) to provide you with APIs that allow you to run such tasks asynchronously.</p>
+
+<h2 id="Blocking_code">Blocking code</h2>
+
+<p>Asynchronous techniques are very useful, particularly in web programming. When a web app runs in a browser and it executes an intensive chunk of code without returning control to the browser, the browser can appear to be frozen. This is called <strong>blocking</strong>; the browser is blocked from continuing to handle user input and perform other tasks until the web app returns control of the processor.</p>
+
+<p>Let's look at a couple of examples that show what we mean by blocking.</p>
+
+<p>In our <a href="https://github.com/mdn/learning-area/tree/master/javascript/asynchronous/introducing/simple-sync.html">simple-sync.html</a> example (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/simple-sync.html">see it running live</a>), we add a click event listener to a button so that when clicked, it runs a time-consuming operation (calculates 10 million dates then logs the final one to the console) and then adds a paragraph to the DOM:</p>
+
+<pre class="brush: js">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>When running the example, open your JavaScript console then click the button — you'll notice that the paragraph does not appear until after the dates have finished being calculated and the console message has been logged. The code runs in the order it appears in the source, and the later operation doesn't run till the earlier operation has finished running.</p>
+
+<div class="notecard note">
+<p><strong>Note</strong>: The previous example is very unrealistic. You would never calculate 10 million dates on a real web app! It does, however, serve to give you the basic idea.</p>
+</div>
+
+<p>In our second example, <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>), we simulate something slightly more realistic that you might come across on a real page. We block user interactivity with the rendering of the UI. In this example, we have two buttons:</p>
+
+<ul>
+ <li>A "Fill canvas" button that when clicked fills the available {{htmlelement("canvas")}} with 1 million blue circles.</li>
+ <li>A "Click me for alert" button that when clicked shows an alert message.</li>
+</ul>
+
+<pre class="brush: js">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>If you click the first button and then quickly click the second one, you'll see that the alert does not appear until the circles have finished being rendered. The first operation blocks the second one until it has finished running.</p>
+
+<div class="notecard 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>Why is this? The answer is because JavaScript, generally speaking, is <strong>single-threaded</strong>. At this point, we need to introduce the concept of <strong>threads</strong>.</p>
+
+<h2 id="Threads">Threads</h2>
+
+<p>A <strong>thread</strong> is basically a single process that a program can use to complete tasks. Each thread can only do a single task at once:</p>
+
+<pre>Task A --&gt; Task B --&gt; Task C</pre>
+
+<p>Each task will be run sequentially; a task has to complete before the next one can be started.</p>
+
+<p>As we said earlier, many computers now have multiple cores, so can do multiple things at once. Programming languages that can support multiple threads can use multiple cores to complete multiple tasks simultaneously:</p>
+
+<pre>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>JavaScript is traditionally single-threaded. Even with multiple cores, you could only get it to run tasks on a single thread, called the <strong>main thread</strong>. Our example from above is run like this:</p>
+
+<pre>Main thread: Render circles to canvas --&gt; Display alert()</pre>
+
+<p>After some time, JavaScript gained some tools to help with such problems. <a href="/en-US/docs/Web/API/Web_Workers_API">Web workers</a> allow you to send some of the JavaScript processing off to a separate thread, called a worker so that you can run multiple JavaScript chunks simultaneously. You'd generally use a worker to run expensive processes off the main thread so that user interaction is not blocked.</p>
+
+<pre> Main thread: Task A --&gt; Task C
+Worker thread: Expensive task B</pre>
+
+<p>With this in mind, have a look at <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>), again with your browser's JavaScript console open. This is a rewrite of our previous example that calculates the 10 million dates in a separate worker thread. Now when you click the button, the browser is able to display the paragraph before the dates have finished calculating. The first operation no longer blocks the second.</p>
+
+<h2 id="Asynchronous_code">Asynchronous code</h2>
+
+<p>Web workers are pretty useful, but they do have their limitations. A major one is they are not able to access the {{Glossary("DOM")}} — you can't get a worker to directly do anything to update the UI. We couldn't render our 1 million blue circles inside our worker; it can basically just do the number crunching.</p>
+
+<p>The second problem is that although code run in a worker is not blocking, it is still basically synchronous. This becomes a problem when a function relies on the results of multiple previous processes to function. Consider the following thread diagrams:</p>
+
+<pre>Main thread: Task A --&gt; Task B</pre>
+
+<p>In this case, let's say Task A is doing something like fetching an image from the server and Task B then does something to the image like applying a filter to it. If you start Task A running and then immediately try to run Task B, you'll get an error, because the image won't be available yet.</p>
+
+<pre> Main thread: Task A --&gt; Task B --&gt; |Task D|
+Worker thread: Task C -----------&gt; | |</pre>
+
+<p>In this case, let's say Task D makes use of the results of both Task B and Task C. If we can guarantee that these results will both be available at the same time, then we might be OK, but this is unlikely. If Task D tries to run when one of its inputs is not yet available, it will throw an error.</p>
+
+<p>To fix such problems, browsers allow us to run certain operations asynchronously. Features like <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a> allow you to set an operation running (e.g. the fetching of an image from the server), and then wait until the result has returned before running another operation:</p>
+
+<pre>Main thread: Task A Task B
+ Promise: |__async operation__|</pre>
+
+<p>Since the operation is happening somewhere else, the main thread is not blocked while the async operation is being processed.</p>
+
+<p>We'll start to look at how we can write asynchronous code in the next article. Exciting stuff, huh? Keep reading!</p>
+
+<h2 id="Conclusion">Conclusion</h2>
+
+<p>Modern software design increasingly revolves around using asynchronous programming, to allow programs to do more than one thing at a time. As you use newer and more powerful APIs, you'll find more cases where the only way to do things is asynchronously. It used to be hard to write asynchronous code. It still takes getting used to, but it's gotten a lot easier. In the rest of this module, we'll explore further why asynchronous code matters and how to design code that avoids some of the problems described above.</p>
+
+<div>{{LearnSidebar}}{{NextMenu("Learn/JavaScript/Asynchronous/Introducing", "Learn/JavaScript/Asynchronous")}}</div>
+
+<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/zh-tw/learn/javascript/asynchronous/index.html b/files/zh-tw/learn/javascript/asynchronous/index.html
new file mode 100644
index 0000000000..f1279adeee
--- /dev/null
+++ b/files/zh-tw/learn/javascript/asynchronous/index.html
@@ -0,0 +1,66 @@
+---
+title: 非同步的 JavaScript
+slug: Learn/JavaScript/Asynchronous
+tags:
+ - Beginner
+ - CodingScripting
+ - Guide
+ - JavaScript
+ - Landing
+ - Promises
+ - async
+ - asynchronous
+ - await
+ - callbacks
+ - requestAnimationFrame
+ - setInterval
+ - setTimeout
+ - 非同步的
+---
+<div>{{LearnSidebar}}</div>
+
+<p class="summary"><span class="seoSummary">在本單元我們來討論非同步的 ({{Glossary("asynchronous")}}) {{Glossary("JavaScript")}} ,為何其如此重要,並了解它如何有效率的處理像是從伺服器獲取資源的這類潛在性阻塞 (blocking) 操作</span></p>
+
+<div class="callout">
+ <h4 id="Looking_to_become_a_front-end_web_developer">想要成為前端開發人員?</h4>
+
+ <p>我們已為您準備一門實現您目標所需要具備的所有基礎知識課程</p>
+
+ <p><a href="/en-US/docs/Learn/Front-end_web_developer"><strong>立即開始</strong></a></p>
+
+</div>
+
+<h2 id="Prerequisites">事前準備</h2>
+
+<p>非同步的 JavaScript 是一個相當進階的主題,因此建議您在嘗試本單元前能先通過 <a href="/zh-TW/docs/Learn/JavaScript/First_steps">JavaScript 初探</a> 以及 <a href="/zh-TW/docs/Learn/JavaScript/Building_blocks">JavaScript 構成元素</a> 單元。</p>
+
+<p>如果您對非同步程式設計的概念還不太熟悉,強烈建議您應該先從 <a href="/zh-TW/docs/Learn/JavaScript/Asynchronous/Concepts">非同步程式設計通用概念</a> 的文章開始學習。如果您已經具備其概念,那麼您或許可以跳至 <a href="/zh-TW/docs/Learn/JavaScript/Asynchronous/Introducing">非同步的 JavaScript 介紹</a> 單元開始。</p>
+
+<div class="note">
+<p><strong>Note</strong>: 如果您正在使用電腦/平板/任何其它無法讓您建立檔案的裝置上,您可以嘗試在 <a href="https://jsbin.com/">JSBin</a> 或是 <a href="https://glitch.com">Glitch</a> 上測試本單元的範例程式碼。</p>
+</div>
+
+<h2 id="Guides">Guides</h2>
+
+<dl>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/Asynchronous/Concepts">非同步程式設計通用概念</a></dt>
+ <dd>
+ <p>在本篇文章我們會介紹一些關於非同步程式設計的重要觀念,以及在網頁瀏覽器和 JavaScript 中的行為。在閱讀其他文章之前您應該先具備這些觀念。</p>
+ </dd>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/Asynchronous/Introducing">非同步的 JavaScript 介紹</a></dt>
+ <dd>在本篇文章中我們會先簡短的回顧我們在同步的 JavaScript 中所遭遇到的問題,並預先看看稍後將會使用哪些非同步的 JavaScript 技巧來解決此問題。</dd>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">協同的非同步 JavaScript: Timeouts 和 intervals</a></dt>
+ <dd>在這裡看看我們在傳統上是如何透過設定的時間到期或是透過定時的方式 (如每秒發生的次數) 讓 Javascript 能夠以非同步的方式執行程式碼,談談這些方法有哪些用處以及存在哪些既有的問題。</dd>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/Asynchronous/Promises">優雅的使用 Promises 來處理非同步操作</a></dt>
+ <dd>Promises 是在 Javascript 語言中相對較新的功能,它能夠讓你延遲活動直到先前的活動回報完成或失敗。這方法對設置一連串的操作並讓其正確的循序執行相當有用。本篇文章向您展示 promises 是如何運作,您將會看到如何被使用在 WebAPIs,以及如何寫出屬於自己的 promises。</dd>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/Asynchronous/Async_await">利用 async 及 await 讓非同步程式設計變得更容易</a></dt>
+ <dd>Promises 在設置上可能會有些複雜並難以理解,因此現代瀏覽器已經實作出 <code>async</code> 函式以及 <code>await</code> 運算子。前者能夠讓標準的函式隱含的使用 promises 方式來實現非同步行為,然而後者可以被用在 <code>async</code> 函式內部,讓程式碼繼續執行之前去等待一個 promises 完成。這能讓我們在鏈結一連串的 promises 的情況之下更加簡潔易懂。</dd>
+ <dt><a href="/zh-TW/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">選擇正確的方法</a></dt>
+ <dd>在結束本單元前,我們將會從先前所討論過的不同程式技巧和功能,幫助您考量在甚麼情況下應該使用哪一個,並適當的提供一些有關常見的陷阱的建議及提醒。</dd>
+</dl>
+
+<h2 id="See_also">參閱</h2>
+
+<ul>
+ <li><a href="https://eloquentjavascript.net/11_async.html">Asynchronous Programming</a> 來自作者為Marijn Haverbeke的極佳的 <a href="https://eloquentjavascript.net/">Eloquent JavaScript</a> 電子書。</li>
+</ul>
diff --git a/files/zh-tw/learn/javascript/asynchronous/introducing/index.html b/files/zh-tw/learn/javascript/asynchronous/introducing/index.html
new file mode 100644
index 0000000000..adaf89c906
--- /dev/null
+++ b/files/zh-tw/learn/javascript/asynchronous/introducing/index.html
@@ -0,0 +1,287 @@
+---
+title: 非同步的 JavaScript 介紹
+slug: Learn/JavaScript/Asynchronous/Introducing
+tags:
+ - Beginner
+ - CodingScripting
+ - Guide
+ - Introducing
+ - JavaScript
+ - Learn
+ - Promises
+ - async
+ - asynchronous
+ - await
+ - callbacks
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Concepts", "Learn/JavaScript/Asynchronous/Timeouts_and_intervals", "Learn/JavaScript/Asynchronous")}}</div>
+
+<p class="summary">在本篇文章中我們會先簡短的回顧我們在同步的 JavaScript 中所遭遇到的問題,並預先看看稍後將會使用哪些非同步的 JavaScript 技巧來解決此問題。</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 gain familiarity with what asynchronous JavaScript is, how it differs from synchronous JavaScript, and what use cases it has.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Synchronous_JavaScript">Synchronous JavaScript</h2>
+
+<p>To allow us to understand what <strong>{{Glossary("asynchronous")}}</strong> JavaScript is, we ought to start off by making sure we understand what <strong>{{Glossary("synchronous")}}</strong> JavaScript is. This section recaps some of the information we saw in the previous article.</p>
+
+<p>A lot of the functionality we have looked at in previous learning area modules is synchronous — you run some code, and the result is returned as soon as the browser can do so. Let's look at a simple example (<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">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>In this block, the lines are executed one after the other:</p>
+
+<ol>
+ <li>We grab a reference to a {{htmlelement("button")}} element that is already available in the DOM.</li>
+ <li>We add a <code><a href="/en-US/docs/Web/API/Element/click_event">click</a></code> event listener to it so that when the button is clicked:
+ <ol>
+ <li>An <code><a href="/en-US/docs/Web/API/Window/alert">alert()</a></code> message appears.</li>
+ <li>Once the alert is dismissed, we create a {{htmlelement("p")}} element.</li>
+ <li>We then give it some text content.</li>
+ <li>Finally, we append the paragraph to the document body.</li>
+ </ol>
+ </li>
+</ol>
+
+<p>While each operation is being processed, nothing else can happen — rendering is paused. This is because as we said in the <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">previous article</a>, <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts#javascript_is_single_threaded">JavaScript is single threaded</a>. Only one thing can happen at a time, on a single main thread, and everything else is blocked until an operation completes.</p>
+
+<p>So in the example above, after you've clicked the button the paragraph won't appear until after the OK button is pressed in the alert box. You can try it for yourself:</p>
+
+<div class="hidden">
+<pre class="brush: html">&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="notecard note">
+<p><strong>Note</strong>: It is important to remember that <code><a href="/en-US/docs/Web/API/Window/alert">alert()</a></code>, while being very useful for demonstrating a synchronous blocking operation, is terrible for use in real world applications.</p>
+</div>
+
+<h2 id="Asynchronous_JavaScript">Asynchronous JavaScript</h2>
+
+<p>For reasons illustrated earlier (e.g. related to blocking), many Web API features now use asynchronous code to run, especially those that access or fetch some kind of resource from an external device, such as fetching a file from the network, accessing a database and returning data from it, accessing a video stream from a web cam, or broadcasting the display to a VR headset.</p>
+
+<p>Why is this difficult to get to work using synchronous code? Let's look at a quick example. When you fetch an image from a server, you can't return the result immediately. That means that the following (pseudocode) wouldn't work:</p>
+
+<pre class="brush: js">let response = fetch('myImage.png'); // fetch is asynchronous
+let blob = response.blob();
+// display your image blob in the UI somehow</pre>
+
+<p>That's because you don't know how long the image will take to download, so when you come to run the second line it will throw an error (possibly intermittently, possibly every time) because the <code>response</code> is not yet available. Instead, you need your code to wait until the <code>response</code> is returned before it tries to do anything else to it.</p>
+
+<p>There are two main types of asynchronous code style you'll come across in JavaScript code, old-style callbacks and newer promise-style code. In the below sections we'll review each of these in turn.</p>
+
+<h2 id="Async_callbacks">Async callbacks</h2>
+
+<p>Async callbacks are functions that are specified as arguments when calling a function which will start executing code in the background. When the background code finishes running, it calls the callback function to let you know the work is done, or to let you know that something of interest has happened. Using callbacks is slightly old-fashioned now, but you'll still see them in use in a number of older-but-still-commonly-used APIs.</p>
+
+<p>An example of an async callback is the second parameter of the {{domxref("EventTarget.addEventListener", "addEventListener()")}} method (as we saw in action above):</p>
+
+<pre class="brush: js">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>The first parameter is the type of event to be listened for, and the second parameter is a callback function that is invoked when the event is fired.</p>
+
+<p>When we pass a callback function as an argument to another function, we are only passing the function's reference as an argument, i.e, the callback function is <strong>not</strong> executed immediately. It is “called back” (hence the name) asynchronously somewhere inside the containing function’s body. The containing function is responsible for executing the callback function when the time comes.</p>
+
+<p>You can write your own function containing a callback easily enough. Let's look at another example that loads a resource via the <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>):</p>
+
+<pre class="brush: js">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>Here we create a <code>displayImage()</code> function that represents a blob passed to it as an object URL, then creates an image to display the URL in, appending it to the document's <code>&lt;body&gt;</code>. However, we then create a <code>loadAsset()</code> function that takes a callback as a parameter, along with a URL to fetch and a content type. It uses <code>XMLHttpRequest</code> (often abbreviated to "XHR") to fetch the resource at the given URL, then pass the response to the callback to do something with. In this case the callback is waiting on the XHR call to finish downloading the resource (using the <code><a href="/en-US/docs/Web/API/XMLHttpRequestEventTarget/onload">onload</a></code> event handler) before it passes it to the callback.</p>
+
+<p>Callbacks are versatile — not only do they allow you to control the order in which functions are run and what data is passed between them, they also allow you to pass data to different functions depending on circumstance. So you could have different actions to run on the response downloaded, such as <code>processJSON()</code>, <code>displayText()</code>, etc.</p>
+
+<p>Note that not all callbacks are async — some run synchronously. An example is when we use {{jsxref("Array.prototype.forEach()")}} to loop through the items in an array (<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">const gods = ['Apollo', 'Artemis', 'Ares', 'Zeus'];
+
+gods.forEach(function (eachName, index){
+ console.log(index + '. ' + eachName);
+});</pre>
+
+<p>In this example we loop through an array of Greek gods and print the index numbers and values to the console. The expected parameter of <code>forEach()</code> is a callback function, which itself takes two parameters, a reference to the array name and index values. However, it doesn't wait for anything — it runs immediately.</p>
+
+<h2 id="Promises">Promises</h2>
+
+<p>Promises are the new style of async code that you'll see used in modern Web APIs. A good example is the <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch">fetch()</a></code> API, which is basically like a modern, more efficient version of {{domxref("XMLHttpRequest")}}. Let's look at a quick example, from our <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Fetching data from the server</a> article:</p>
+
+<pre class="brush: js">fetch('products.json').then(function(response) {
+  return response.json();
+}).then(function(json) {
+  let products = json;
+  initialize(products);
+}).catch(function(err) {
+  console.log('Fetch problem: ' + err.message);
+});</pre>
+
+<div class="notecard 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/can-script.js">see the source here</a>, and also <a href="https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/">see it running live</a>).</p>
+</div>
+
+<p>Here we see <code>fetch</code><code>()</code> taking a single parameter — the URL of a resource you want to fetch from the network — and returning a <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">promise</a>. The promise is an object representing the completion or failure of the async operation. It represents an intermediate state, as it were. In essence, it's the browser's way of saying "I promise to get back to you with the answer as soon as I can," hence the name "promise."</p>
+
+<p>This concept can take practice to get used to; it feels a little like {{interwiki("wikipedia", "Schrödinger's cat")}} in action. Neither of the possible outcomes have happened yet, so the fetch operation is currently waiting on the result of the browser trying to complete the operation at some point in the future. We've then got three further code blocks chained onto the end of the <code>fetch()</code>:</p>
+
+<ul>
+ <li>Two <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">then()</a></code> blocks. Both contain a callback function that will run if the previous operation is successful, and each callback receives as input the result of the previous successful operation, so you can go forward and do something else to it. Each <code>.then()</code> block returns another promise, meaning that you can chain multiple <code>.then()</code> blocks onto each other, so multiple asynchronous operations can be made to run in order, one after another.</li>
+ <li>The <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch">catch()</a></code> block at the end runs if any of the <code>.then()</code> blocks fail — in a similar way to synchronous <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/try...catch">try...catch</a></code> blocks, an error object is made available inside the <code>catch()</code>, which can be used to report the kind of error that has occurred. Note however that synchronous <code>try...catch</code> won't work with promises, although it will work with <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">async/await</a>, as you'll learn later on.</li>
+</ul>
+
+<div class="notecard 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>Async operations like promises are put into an <strong>event queue</strong>, which runs after the main thread has finished processing so that they <em>do not block</em> subsequent JavaScript code from running. The queued operations will complete as soon as possible then return their results to the JavaScript environment.</p>
+
+<h3 id="Promises_versus_callbacks">Promises versus callbacks</h3>
+
+<p>Promises have some similarities to old-style callbacks. They are essentially a returned object to which you attach callback functions, rather than having to pass callbacks into a function.</p>
+
+<p>However, promises are specifically made for handling async operations, and have many advantages over old-style callbacks:</p>
+
+<ul>
+ <li>You can chain multiple async operations together using multiple <code>.then()</code> operations, passing the result of one into the next one as an input. This is much harder to do with callbacks, which often ends up with a messy "pyramid of doom" (also known as <a href="http://callbackhell.com/">callback hell</a>).</li>
+ <li>Promise callbacks are always called in the strict order they are placed in the event queue.</li>
+ <li>Error handling is much better — all errors are handled by a single <code>.catch()</code> block at the end of the block, rather than being individually handled in each level of the "pyramid".</li>
+ <li>Promises avoid inversion of control, unlike old-style callbacks, which lose full control of how the function will be executed when passing a callback to a third-party library.</li>
+</ul>
+
+<h2 id="The_nature_of_asynchronous_code">The nature of asynchronous code</h2>
+
+<p>Let's explore an example that further illustrates the nature of async code, showing what can happen when we are not fully aware of code execution order and the problems of trying to treat asynchronous code like synchronous code. The following example is fairly similar to what we've seen before (<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>). One difference is that we've included a number of {{domxref("console.log()")}} statements to illustrate an order that you might think the code would execute in.</p>
+
+<pre class="brush: js">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>The browser will begin executing the code, see the first <code>console.log()</code> statement (<code>Starting</code>) and execute it, and then create the <code>image</code> variable.</p>
+
+<p>It will then move to the next line and begin executing the <code>fetch()</code> block but, because <code>fetch()</code> executes asynchronously without blocking, code execution continues after the promise-related code, thereby reaching the final <code>console.log()</code> statement (<code>All done!</code>) and outputting it to the console.</p>
+
+<p>Only once the <code>fetch()</code> block has completely finished running and delivering its result through the <code>.then()</code> blocks will we finally see the second <code>console.log()</code> message (<code>It worked :)</code>) appear. So the messages have appeared in a different order to what you might expect:</p>
+
+<ul>
+ <li>Starting</li>
+ <li>All done!</li>
+ <li>It worked :)</li>
+</ul>
+
+<p>If this confuses you, then consider the following smaller example:</p>
+
+<pre class="brush: js">console.log("registering click handler");
+
+button.addEventListener('click', () =&gt; {
+ console.log("get click");
+});
+
+console.log("all done");</pre>
+
+<p>This is very similar in behavior — the first and third <code>console.log()</code> messages will be shown immediately, but the second one is blocked from running until someone clicks the mouse button. The previous example works in the same way, except that in that case the second message is blocked on the promise chain fetching a resource then displaying it on screen, rather than a click.</p>
+
+<p>In a less trivial code example, this kind of setup could cause a problem — you can't include an async code block that returns a result, which you then rely on later in a sync code block. You just can't guarantee that the async function will return before the browser has processed the sync block.</p>
+
+<p>To see this in action, try taking a local copy of <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/async-sync.html">our example</a>, and changing the fourth <code>console.log()</code> call to the following:</p>
+
+<pre class="brush: js">console.log ('All done! ' + image.src + 'displayed.');</pre>
+
+<p>You should now get an error in your console instead of the third message:</p>
+
+<pre><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>This is because at the time the browser tries to run the third <code>console.log()</code> statement, the <code>fetch()</code> block has not finished running so the <code>image</code> variable has not been given a value.</p>
+
+<div class="notecard 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>To fix the problematic <code>fetch()</code> example and make the three <code>console.log()</code> statements appear in the desired order, you could make the third <code>console.log()</code> statement run async as well. This can be done by moving it inside another <code>.then()</code> block chained onto the end of the second one, or by moving it inside the second <code>then()</code> block. Try fixing this now.</p>
+
+<div class="notecard 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>
+
+<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/zh-tw/learn/javascript/asynchronous/promises/index.html b/files/zh-tw/learn/javascript/asynchronous/promises/index.html
new file mode 100644
index 0000000000..cbac933963
--- /dev/null
+++ b/files/zh-tw/learn/javascript/asynchronous/promises/index.html
@@ -0,0 +1,600 @@
+---
+title: 優雅的使用 Promises 來處理非同步操作
+slug: Learn/JavaScript/Asynchronous/Promises
+tags:
+ - Beginner
+ - CodingScripting
+ - Guide
+ - JavaScript
+ - Learn
+ - Promises
+ - async
+ - asynchronous
+ - catch
+ - finally
+ - then
+---
+<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 語言中相對較新的功能,它能夠讓你延遲活動直到先前的活動回報完成或失敗。這方法對設置一連串的操作並讓其正確的循序執行相當有用。本篇文章向您展示 promises 是如何運作,您將會看到如何被使用在 WebAPIs,以及如何寫出屬於自己的 promises。</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>We looked at <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a> briefly in the first article of the course, but here we'll look at them in a lot more depth.</p>
+
+<p>Essentially, a Promise is an object that represents an intermediate state of an operation — in effect, a <em>promise</em> that a result of some kind will be returned at some point in the future. There is no guarantee of exactly when the operation will complete and the result will be returned, but there <em>is</em> a guarantee that when the result is available, or the promise fails, the code you provide will be executed in order to do something else with a successful result, or to gracefully handle a failure case.</p>
+
+<p>Generally, you are less interested in the amount of time an async operation will take to return its result (unless of course, it takes <em>far</em> too long!), and more interested in being able to respond to it being returned, whenever that is. And of course, it's nice that it doesn't block the rest of the code execution.</p>
+
+<p>One of the most common engagements you'll have with promises is with web APIs that return a promise. Let's consider a hypothetical video chat application. The application has a window with a list of the user's friends, and clicking on a button next to a user starts a video call to that user.</p>
+
+<p>That button's handler calls {{domxref("MediaDevices.getUserMedia", "getUserMedia()")}} in order to get access to the user's camera and microphone. Since <code>getUserMedia()</code> has to ensure that the user has permission to use those devices <em>and</em> ask the user which microphone to use and which camera to use (or whether to be a voice-only call, among other possible options), it can block until not only all of those decisions are made, but also the camera and microphone have been engaged. Also, the user may not respond immediately to these permission requests. This can potentially take a long time.</p>
+
+<p>Since the call to <code>getUserMedia()</code> is made from the browser's main thread, the entire browser is blocked until <code>getUserMedia()</code> returns! Obviously, that's not an acceptable option; without promises, everything in the browser becomes unusable until the user decides what to do about the camera and microphone. So instead of waiting for the user, getting the chosen devices enabled, and directly returning the {{domxref("MediaStream")}} for the stream created from the selected sources, <code>getUserMedia()</code> returns a {{jsxref("promise")}} which is resolved with the {{domxref("MediaStream")}} once it's available.</p>
+
+<p>The code that the video chat application would use might look something like this:</p>
+
+<pre class="brush: js">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>This function starts by using a function called <code>setStatusMessage()</code> to update a status display with the message "Calling...", indicating that a call is being attempted. It then calls <code>getUserMedia()</code>, asking for a stream that has both video and audio tracks, then once that's been obtained, sets up a video element to show the stream coming from the camera as a "self view," then takes each of the stream's tracks and adds them to the <a href="/en-US/docs/Web/API/WebRTC_API">WebRTC</a> {{domxref("RTCPeerConnection")}} representing a connection to another user. After that, the status display is updated to say "Connected".</p>
+
+<p>If <code>getUserMedia()</code> fails, the <code>catch</code> block runs. This uses <code>setStatusMessage()</code> to update the status box to indicate that an error occurred.</p>
+
+<p>The important thing here is that the <code>getUserMedia()</code> call returns almost immediately, even if the camera stream hasn't been obtained yet. Even if the <code>handleCallButton()</code> function has already returned to the code that called it, when <code>getUserMedia()</code> has finished working, it calls the handler you provide. As long as the app doesn't assume that streaming has begun, it can just keep on running.</p>
+
+<div class="notecard note">
+<p><strong>Note:</strong> You can learn more about this somewhat advanced topic, if you're interested, in the article <a href="/en-US/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>To fully understand why promises are a good thing, it helps to think back to old-style callbacks and to appreciate why they are problematic.</p>
+
+<p>Let's talk about ordering pizza as an analogy. There are certain steps that you have to take for your order to be successful, which doesn't really make sense to try to execute out of order, or in order but before each previous step has quite finished:</p>
+
+<ol>
+ <li>You choose what toppings you want. This can take a while if you are indecisive, and may fail if you just can't make up your mind, or decide to get a curry instead.</li>
+ <li>You then place your order. This can take a while to return a pizza and may fail if the restaurant does not have the required ingredients to cook it.</li>
+ <li>You then collect your pizza and eat. This might fail if, say, you forgot your wallet so can't pay for the pizza!</li>
+</ol>
+
+<p>With old-style <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing#callbacks">callbacks</a>, a pseudo-code representation of the above functionality might look something like this:</p>
+
+<pre class="brush: js">chooseToppings(function(toppings) {
+ placeOrder(toppings, function(order) {
+ collectOrder(order, function(pizza) {
+ eatPizza(pizza);
+ }, failureCallback);
+ }, failureCallback);
+}, failureCallback);</pre>
+
+<p>This is messy and hard to read (often referred to as "<a href="http://callbackhell.com/">callback hell</a>"), requires the <code>failureCallback()</code> to be called multiple times (once for each nested function), with other issues besides.</p>
+
+<h3 id="Improvements_with_promises">Improvements with promises</h3>
+
+<p>Promises make situations like the above much easier to write, parse, and run. If we represented the above pseudo-code using asynchronous promises instead, we'd end up with something like this:</p>
+
+<pre class="brush: js">chooseToppings()
+.then(function(toppings) {
+ return placeOrder(toppings);
+})
+.then(function(order) {
+ return collectOrder(order);
+})
+.then(function(pizza) {
+ eatPizza(pizza);
+})
+.catch(failureCallback);</pre>
+
+<p>This is much better — it is easier to see what is going on, we only need a single <code>.catch()</code> block to handle all the errors, it doesn't block the main thread (so we can keep playing video games while we wait for the pizza to be ready to collect), and each operation is guaranteed to wait for previous operations to complete before running. We're able to chain multiple asynchronous actions to occur one after another this way because each <code>.then()</code> block returns a new promise that resolves when the <code>.then()</code> block is done running. Clever, right?</p>
+
+<p>Using arrow functions, you can simplify the code even further:</p>
+
+<pre class="brush: js">chooseToppings()
+.then(toppings =&gt;
+ placeOrder(toppings)
+)
+.then(order =&gt;
+ collectOrder(order)
+)
+.then(pizza =&gt;
+ eatPizza(pizza)
+)
+.catch(failureCallback);</pre>
+
+<p>Or even this:</p>
+
+<pre class="brush: js">chooseToppings()
+.then(toppings =&gt; placeOrder(toppings))
+.then(order =&gt; collectOrder(order))
+.then(pizza =&gt; eatPizza(pizza))
+.catch(failureCallback);</pre>
+
+<p>This works because with arrow functions <code>() =&gt; x</code> is valid shorthand for <code>() =&gt; { return x; }</code>.</p>
+
+<p>You could even do this, since the functions just pass their arguments directly, so there isn't any need for that extra layer of functions:</p>
+
+<pre class="brush: js">chooseToppings().then(placeOrder).then(collectOrder).then(eatPizza).catch(failureCallback);</pre>
+
+<p>This is not quite as easy to read, however, and this syntax might not be usable if your blocks are more complex than what we've shown here.</p>
+
+<div class="notecard note">
+<p><strong>Note</strong>: You can make further improvements with <code>async</code>/<code>await</code> syntax, which we'll dig into in the next article.</p>
+</div>
+
+<p>At their most basic, promises are similar to event listeners, but with a few differences:</p>
+
+<ul>
+ <li>A promise can only succeed or fail once. It cannot succeed or fail twice and it cannot switch from success to failure or vice versa once the operation has completed.</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>Promises are important to understand because most modern Web APIs use them for functions that perform potentially lengthy tasks. To use modern web technologies you'll need to use promises. Later on in the chapter, we'll look at how to write your own promise, but for now, we'll look at some simple examples that you'll encounter in Web APIs.</p>
+
+<p>In the first example, we'll use the <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch">fetch()</a></code> method to fetch an image from the web, the {{domxref("Body.blob", "blob()")}} method to transform the fetch response's raw body contents into a {{domxref("Blob")}} object, and then display that blob inside an {{htmlelement("img")}} element. This is very similar to the example we looked at in the <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing#asynchronous_javascript">first article of the series</a>, but we'll do it a bit differently as we get you building your own promise-based code.</p>
+
+<div class="notecard 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>First of all, download our <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">simple HTML template</a> and the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/coffee.jpg">sample image file</a> that we'll fetch.</p>
+ </li>
+ <li>
+ <p>Add a {{htmlelement("script")}} element at the bottom of the HTML {{htmlelement("body")}}.</p>
+ </li>
+ <li>
+ <p>Inside your {{HTMLElement("script")}} element, add the following line:</p>
+
+ <pre class="brush: js">let promise = fetch('coffee.jpg');</pre>
+
+ <p>This calls the <code>fetch()</code> method, passing it the URL of the image to fetch from the network as a parameter. This can also take an options object as an optional second parameter, but we are just using the simplest version for now. We are storing the promise object returned by <code>fetch()</code> inside a variable called <code>promise</code>. As we said before, this object represents an intermediate state that is initially neither success nor failure — the official term for a promise in this state is <strong>pending</strong>.</p>
+ </li>
+ <li>
+ <p>To respond to the successful completion of the operation whenever that occurs (in this case, when a {{domxref("Response")}} is returned), we invoke the <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">.then()</a></code> method of the promise object. The callback inside the <code>.then()</code> block runs only when the promise call completes successfully and returns the {{domxref("Response")}} object — in promise-speak, when it has been <strong>fulfilled</strong>. It is passed the returned {{domxref("Response")}} object as a parameter.</p>
+
+ <div class="notecard 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 <code>.then()</code> will only run once for each time it is used, whereas an event listener could be invoked multiple times.</p>
+ </div>
+
+ <p>We immediately run the <code>blob()</code> method on this response to ensure that the response body is fully downloaded, and when it is available transform it into a <code>Blob</code> object that we can do something with. The result of this is returned like so:</p>
+
+ <pre class="brush: js">response =&gt; response.blob()</pre>
+
+ <p>which is shorthand for</p>
+
+ <pre class="brush: js">function(response) {
+ return response.blob();
+}</pre>
+
+ <p>Unfortunately, we need to do slightly more than this. Fetch promises do not fail on 404 or 500 errors — only on something catastrophic like a network failure. Instead, they succeed, but with the <code><a href="/en-US/docs/Web/API/Response/ok">response.ok</a></code> property set to <code>false</code>. To produce an error on a 404, for example, we need to check the value of <code>response.ok</code>, and if <code>false</code>, throw an error, only returning the blob if it is <code>true</code>. This can be done like so — add the following lines below your first line of JavaScript.</p>
+
+ <pre class="brush: js">let promise2 = promise.then(response =&gt; {
+  if (!response.ok) {
+    throw new Error(`HTTP error! status: ${response.status}`);
+  } else {
+    return response.blob();
+  }
+});</pre>
+ </li>
+ <li>
+ <p>Each call to <code>.then()</code> creates a new promise. This is very useful; because the <code>blob()</code> method also returns a promise, we can handle the <code>Blob</code> object it returns on fulfillment by invoking the <code>.then()</code> method of the second promise. Because we want to do something a bit more complex to the blob than just run a single method on it and return the result, we'll need to wrap the function body in curly braces this time (otherwise it'll throw an error).</p>
+
+ <p>Add the following to the end of your code:</p>
+
+ <pre class="brush: js">let promise3 = promise2.then(myBlob =&gt; {
+
+})</pre>
+ </li>
+ <li>
+ <p>Now let's fill in the body of the <code>.then()</code> callback. Add the following lines inside the curly braces:</p>
+
+ <pre class="brush: js">let objectURL = URL.createObjectURL(myBlob);
+let image = document.createElement('img');
+image.src = objectURL;
+document.body.appendChild(image);</pre>
+
+ <p>Here we are running the {{domxref("URL.createObjectURL()")}} method, passing it as a parameter the <code>Blob</code> returned when the second promise fulfills. This will return a URL pointing to the object. Then we create an {{htmlelement("img")}} element, set its <code>src</code> attribute to equal the object URL and append it to the DOM, so the image will display on the page!</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="notecard 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>Something is missing — currently, there is nothing to explicitly handle errors if one of the promises fails (<strong>rejects</strong>, in promise-speak). We can add error handling by running the <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch">.catch()</a></code> method off the previous promise. Add this now:</p>
+
+<pre class="brush: js">let errorCase = promise3.catch(e =&gt; {
+ console.log('There has been a problem with your fetch operation: ' + e.message);
+});</pre>
+
+<p>To see this in action, try misspelling the URL to the image and reloading the page. The error will be reported in the console of your browser's developer tools.</p>
+
+<p>This doesn't do much more than it would if you just didn't bother including the <code>.catch()</code> block at all, but think about it — this allows us to control error handling exactly how we want. In a real app, your <code>.catch()</code> block could retry fetching the image, or show a default image, or prompt the user to provide a different image URL, or whatever.</p>
+
+<div class="notecard 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>This is a very longhand way of writing this out; we've deliberately done this to help you understand what is going on clearly. As shown earlier on in the article, you can chain together <code>.then()</code> blocks (and also <code>.catch()</code> blocks). The above code could also be written like this (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">fetch('coffee.jpg')
+.then(response =&gt; {
+  if (!response.ok) {
+    throw new Error(`HTTP error! status: ${response.status}`);
+  } else {
+    return 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>Bear in mind that the value returned by a fulfilled promise becomes the parameter passed to the next <code>.then()</code> block's callback function.</p>
+
+<div class="notecard 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>There was a lot to cover in the above section, so let's go back over it quickly to give you a <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises#promise_terminology_recap">short guide that you can bookmark</a> and use to refresh your memory in the future. You should also go over the above section again a few more time to make sure these concepts stick.</p>
+
+<ol>
+ <li>When a promise is created, it is neither in a success or failure state. It is said to be <strong>pending</strong>.</li>
+ <li>When a promise returns, it is said to be <strong>resolved</strong>.
+ <ol>
+ <li>A successfully resolved promise is said to be <strong>fulfilled</strong>. It returns a value, which can be accessed by chaining a <code>.then()</code> block onto the end of the promise chain. The callback function inside the <code>.then()</code> block will contain the promise's return value.</li>
+ <li>An unsuccessful resolved promise is said to be <strong>rejected</strong>. It returns a <strong>reason</strong>, an error message stating why the promise was rejected. This reason can be accessed by chaining a <code>.catch()</code> block onto the end of the promise chain.</li>
+ </ol>
+ </li>
+</ol>
+
+<h2 id="Running_code_in_response_to_multiple_promises_fulfilling">Running code in response to multiple promises fulfilling</h2>
+
+<p>The above example showed us some of the real basics of using promises. Now let's look at some more advanced features. For a start, chaining processes to occur one after the other is all fine, but what if you want to run some code only after a whole bunch of promises have <em>all</em> fulfilled?</p>
+
+<p>You can do this with the ingeniously named <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all">Promise.all()</a></code> static method. This takes an array of promises as an input parameter and returns a new <code>Promise</code> object that will fulfil only if and when <em>all</em> promises in the array fulfil. It looks something like this:</p>
+
+<pre class="brush: js">Promise.all([a, b, c]).then(values =&gt; {
+ ...
+});</pre>
+
+<p>If they all fulfil, the chained <code>.then()</code> block's callback function will be passed an array containing all those results as a parameter. If any of the promises passed to <code>Promise.all()</code> reject, the whole block will reject.</p>
+
+<p>This can be very useful. Imagine that we’re fetching information to dynamically populate a UI feature on our page with content. In many cases, it makes sense to receive all the data and only then show the complete content, rather than displaying partial information.</p>
+
+<p>Let's build another example to show this in action.</p>
+
+<ol>
+ <li>
+ <p>Download a fresh copy of our <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">page template</a>, and again put a <code>&lt;script&gt;</code> element just before the closing <code>&lt;/body&gt;</code> tag.</p>
+ </li>
+ <li>
+ <p>Download our source files (<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>), or feel free to substitute your own.</p>
+ </li>
+ <li>
+ <p>In our script, we'll first define a function that returns the promises we want to send to <code>Promise.all()</code>. This would be easy if we just wanted to run the <code>Promise.all()</code> block in response to three <code>fetch()</code> operations completing. We could just do something like:</p>
+
+ <pre class="brush: js">let a = fetch(url1);
+let b = fetch(url2);
+let c = fetch(url3);
+
+Promise.all([a, b, c]).then(values =&gt; {
+ ...
+});</pre>
+
+ <p>When the promise is fulfilled, the <code>values</code> passed into the fulfillment handler would contain three <code>Response</code> objects, one for each of the <code>fetch()</code> operations that have completed.</p>
+
+ <p>However, we don't want to do this. Our code doesn't care when the <code>fetch()</code> operations are done. Instead, what we want is the loaded data. That means we want to run the <code>Promise.all()</code> block when we get back usable blobs representing the images, and a usable text string. We can write a function that does this; add the following inside your <code>&lt;script&gt;</code> element:</p>
+
+ <pre class="brush: js">function fetchAndDecode(url, type) {
+  return fetch(url).then(response =&gt; {
+    if(!response.ok) {
+      throw new Error(`HTTP error! status: ${response.status}`);
+    } else {
+      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);
+  });
+}</pre>
+
+ <p>This looks a bit complex, so let's run through it step by step:</p>
+
+ <ol>
+ <li>First of all, we define the function, passing it a URL and a string representing the type of resource it is fetching.</li>
+ <li>Inside the function body, we have a similar structure to what we saw in the first example — we call the <code>fetch()</code> function to fetch the resource at the specified URL, then chain it onto another promise that returns the decoded (or "read") response body. This was always the <code>blob()</code> method in the previous example.</li>
+ <li>However, two things are different here:
+ <ul>
+ <li>First of all, the second promise we return is different depending on what the <code>type</code> value is. Inside the <code>.then()</code> callback function, we include a simple <code>if ... else if</code> statement to return a different promise depending on what type of file we need to decode (in this case we've got a choice of <code>blob</code> or <code>text</code>, but it would be easy to extend this to deal with other types as well).</li>
+ <li>Second, we have added the <code>return</code> keyword before the <code>fetch()</code> call. The effect this has is to run the entire chain and then run the final result (i.e. the promise returned by <code>blob()</code> or <code>text()</code>) as the return value of the function we've just defined. In effect, the <code>return</code> statements pass the results back up the chain to the top.</li>
+ </ul>
+ </li>
+ <li>
+ <p>At the end of the block, we chain on a <code>.catch()</code> call, to handle any error cases that may occur with any of the promises passed in the array to <code>.all()</code>. If any of the promises reject, the <code>.catch()</code> block will let you know which one had a problem. The <code>.all()</code> block (see below) will still fulfill, but it won't display the resources that had problems. Remember that, once you handle the promise with a  <code>.catch()</code> block, the resulting promise is considered resolved but with a value of <code>undefined</code>; that's why in this case the <code>.all()</code> block will always get fulfilled. If you wanted the <code>.all()</code> to reject, you'd have to chain the <code>.catch()</code> block on to the end of the <code>.all()</code> instead. </p>
+ </li>
+ </ol>
+
+ <p>The code inside the function body is async and promise-based, therefore in effect, the entire function acts like a promise — convenient.</p>
+ </li>
+ <li>
+ <p>Next, we call our function three times to begin the process of fetching and decoding the images and text and store each of the returned promises in a variable. Add the following below your previous code:</p>
+
+ <pre class="brush: js">let coffee = fetchAndDecode('coffee.jpg', 'blob');
+let tea = fetchAndDecode('tea.jpg', 'blob');
+let description = fetchAndDecode('description.txt', 'text');</pre>
+ </li>
+ <li>
+ <p>Next, we will define a <code>Promise.all()</code> block to run some code only when all three of the promises stored above have successfully fulfilled. To begin with, add a block with an empty callback function inside the <code>.then()</code> call, like so:</p>
+
+ <pre class="brush: js">Promise.all([coffee, tea, description]).then(values =&gt; {
+
+});</pre>
+
+ <p>You can see that it takes an array containing the promises as a parameter. The <code>.then()</code> callback function will only run when all three promises resolve; when that happens, it will be passed an array containing the results from the individual promises (i.e. the decoded response bodies), kind of like [coffee-results, tea-results, description-results].</p>
+ </li>
+ <li>
+ <p>Finally, add the following inside the callback. Here we use some fairly simple sync code to store the results in separate variables (creating object URLs from the blobs), then display the images and text on the page.</p>
+
+ <pre class="brush: js">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>Save and refresh and you should see your UI components all loaded, albeit in a not particularly attractive way!</p>
+ </li>
+</ol>
+
+<p>The code we provided here for displaying the items is fairly rudimentary but works as an explainer for now.</p>
+
+<div class="notecard 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="notecard 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>There will be cases where you want to run a final block of code after a promise completes, regardless of whether it fulfilled or rejected. Previously you'd have to include the same code in both the <code>.then()</code> and <code>.catch()</code> callbacks, for example:</p>
+
+<pre class="brush: js">myPromise
+.then(response =&gt; {
+ doSomething(response);
+ runFinalCode();
+})
+.catch(e =&gt; {
+ returnError(e);
+ runFinalCode();
+});</pre>
+
+<p>In more recent modern browsers, the <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally">.finally()</a></code> method is available, which can be chained onto the end of your regular promise chain allowing you to cut down on code repetition and do things more elegantly. The above code can now be written as follows:</p>
+
+<pre class="brush: js">myPromise
+.then(response =&gt; {
+ doSomething(response);
+})
+.catch(e =&gt; {
+ returnError(e);
+})
+.finally(() =&gt; {
+ runFinalCode();
+});</pre>
+
+<p>For a real example, take a look at our <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). This works the same as the <code>Promise.all()</code> demo we looked at in the above section, except that in the <code>fetchAndDecode()</code> function we chain a <code>finally()</code> call on to the end of the chain:</p>
+
+<pre class="brush: js">function fetchAndDecode(url, type) {
+ return fetch(url).then(response =&gt; {
+ if(!response.ok) {
+      throw new Error(`HTTP error! status: ${response.status}`);
+    } else {
+      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>This logs a simple message to the console to tell us when each fetch attempt has finished.</p>
+
+<div class="notecard 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>The good news is that, in a way, you've already built your own promises. When you've chained multiple promises together with <code>.then()</code> blocks, or otherwise combined them to create custom functionality, you are already making your own custom async promise-based functions. Take our <code>fetchAndDecode()</code> function from the previous examples, for example.</p>
+
+<p>Combining different promise-based APIs together to create custom functionality is by far the most common way you'll do custom things with promises, and shows the flexibility and power of basing most modern APIs around the same principle. There is another way, however.</p>
+
+<h3 id="Using_the_Promise_constructor">Using the Promise() constructor</h3>
+
+<p>It is possible to build your own promises using the <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise()</a></code> constructor. The main situation in which you'll want to do this is when you've got code based on an old-school asynchronous API that is not promise-based, which you want to promisify. This comes in handy when you need to use existing, older project code, libraries, or frameworks along with modern promise-based code.</p>
+
+<p>Let's have a look at a simple example to get you started — here we wrap a <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout">setTimeout()</a></code> call with a promise — this runs a function after two seconds that resolves the promise (using the passed <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve">resolve()</a></code> call) with a string of "Success!".</p>
+
+<pre class="brush: js">let timeoutPromise = new Promise((resolve, reject) =&gt; {
+ setTimeout(function(){
+ resolve('Success!');
+ }, 2000);
+});</pre>
+
+<p><code>resolve()</code> and <code>reject()</code> are functions that you call to fulfil or reject the newly-created promise. In this case, the promise fulfills with a string of "Success!".</p>
+
+<p>So when you call this promise, you can chain a <code>.then()</code> block onto the end of it and it will be passed a string of "Success!". In the below code we alert that message:</p>
+
+<pre class="brush: js">timeoutPromise
+.then((message) =&gt; {
+ alert(message);
+})</pre>
+
+<p>or even just</p>
+
+<pre class="brush: js">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>The above example is not very flexible — the promise can only ever fulfil with a single string, and it doesn't have any kind of <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject">reject()</a></code> condition specified (admittedly, <code>setTimeout()</code> doesn't really have a fail condition, so it doesn't matter for this simple example).</p>
+
+<div class="notecard 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>We can create a promise that rejects using the <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject">reject()</a></code> method — just like <code>resolve()</code>, this takes a single value, but in this case, it is the reason to reject with, i.e., the error that will be passed into the <code>.catch()</code> block.</p>
+
+<p>Let's extend the previous example to have some <code>reject()</code> conditions as well as allowing different messages to be passed upon success.</p>
+
+<p>Take a copy of the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/custom-promise.html">previous example</a>, and replace the existing <code>timeoutPromise()</code> definition with this:</p>
+
+<pre class="brush: js">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>Here we are passing two arguments into a custom function — a message to do something with, and the time interval to pass before doing the thing. Inside the function we then return a new <code>Promise</code> object — invoking the function will return the promise we want to use.</p>
+
+<p>Inside the Promise constructor, we do several checks inside <code>if ... else</code> structures:</p>
+
+<ol>
+ <li>First of all, we check to see if the message is appropriate for being alerted. If it is an empty string or not a string at all, we reject the promise with a suitable error message.</li>
+ <li>Next, we check to see if the interval is an appropriate interval value. If it is negative or not a number, we reject the promise with a suitable error message.</li>
+ <li>Finally, if the parameters both look OK, we resolve the promise with the specified message after the specified interval has passed using <code>setTimeout()</code>.</li>
+</ol>
+
+<p>Since the <code>timeoutPromise()</code> function returns a <code>Promise</code>, we can chain <code>.then()</code>, <code>.catch()</code>, etc. onto it to make use of its functionality. Let's use it now — replace the previous <code>timeoutPromise</code> usage with this one:</p>
+
+<pre class="brush: js">timeoutPromise('Hello there!', 1000)
+.then(message =&gt; {
+ alert(message);
+})
+.catch(e =&gt; {
+ console.log('Error: ' + e);
+});</pre>
+
+<p>When you save and run the code as is, after one second you'll get the message alerted. Now try setting the message to an empty string or the interval to a negative number, for example, and you'll be able to see the promise reject with the appropriate error messages! You could also try doing something else with the resolved message rather than just alerting it.</p>
+
+<div class="notecard 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>The above example was kept deliberately simple to make the concepts easy to understand, but it is not really very async. The asynchronous nature is basically faked using <code>setTimeout()</code>, although it does still show that promises are useful for creating a custom function with a sensible flow of operations, good error handling, etc.</p>
+
+<p>One example we'd like to invite you to study, which does show a useful async application of the <code>Promise()</code> constructor, is <a href="https://github.com/jakearchibald/idb/">Jake Archibald's idb library</a>. This takes the <a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB API</a>, which is an old-style callback-based API for storing and retrieving data on the client-side, and allows you to use it with promises. In the code you'll see the same kind of techniques we discussed above being used there. The following block converts the basic request model used by many IndexedDB methods to use promises (<a href="https://github.com/jakearchibald/idb/blob/01082ad696eef05e9c913f55a17cda7b3016b12c/build/esm/wrap-idb-value.js#L30">see this code, for example</a>).</p>
+
+<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/zh-tw/learn/javascript/asynchronous/timeouts_and_intervals/index.html b/files/zh-tw/learn/javascript/asynchronous/timeouts_and_intervals/index.html
new file mode 100644
index 0000000000..9e076bcad4
--- /dev/null
+++ b/files/zh-tw/learn/javascript/asynchronous/timeouts_and_intervals/index.html
@@ -0,0 +1,646 @@
+---
+title: '協同的非同步 JavaScript: Timeouts 和 intervals'
+slug: Learn/JavaScript/Asynchronous/Timeouts_and_intervals
+tags:
+ - Animation
+ - Beginner
+ - CodingScripting
+ - Guide
+ - Intervals
+ - JavaScript
+ - Loops
+ - asynchronous
+ - requestAnimationFrame
+ - setInterval
+ - setTimeout
+ - timeouts
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Introducing", "Learn/JavaScript/Asynchronous/Promises", "Learn/JavaScript/Asynchronous")}}</div>
+
+<p class="summary">在這裡看看我們在傳統上是如何透過設定的時間到期或是透過定時的方式 (如每秒發生的次數) 讓 Javascript 能夠以非同步的方式執行程式碼,談談這些方法有哪些用處以及存在哪些既有的問題。</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>For a long time, the web platform has offered JavaScript programmers a number of functions that allow them to asynchronously execute code after a certain time interval has elapsed, and to repeatedly execute a block of code asynchronously until you tell it to stop.</p>
+
+<p>These functions are:</p>
+
+<dl>
+ <dt><code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout">setTimeout()</a></code></dt>
+ <dd>Execute a specified block of code once after a specified time has elapsed.</dd>
+ <dt><code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval">setInterval()</a></code></dt>
+ <dd>Execute a specified block of code repeatedly with a fixed time delay between each call.</dd>
+ <dt><code><a href="/en-US/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame()</a></code></dt>
+ <dd>The modern version of <code>setInterval()</code>. Executes a specified block of code before the browser next repaints the display, allowing an animation to be run at a suitable framerate regardless of the environment it is being run in.</dd>
+</dl>
+
+<p>The asynchronous code set up by these functions runs on the main thread (after their specified timer has elapsed).</p>
+
+<p>It's important to know that you can (and often will) run other code before a <code>setTimeout()</code> call executes, or between iterations of <code>setInterval()</code>. Depending on how processor-intensive these operations are, they can delay your async code even further, as any async code will execute only <em>after</em> the main thread is available. (In other words, when the stack is empty.)  You will learn more on this matter as you progress through this article.</p>
+
+<p>In any case, these functions are used for running constant animations and other background processing on a web site or application. In the following sections we will show you how they can be used.</p>
+
+<h2 id="setTimeout">setTimeout()</h2>
+
+<p>As we said before, <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout">setTimeout()</a></code> executes a particular block of code once after a specified time has elapsed. It takes the following parameters:</p>
+
+<ul>
+ <li>A function to run, or a reference to a function defined elsewhere.</li>
+ <li>A number representing the time interval in milliseconds (1000 milliseconds equals 1 second) to wait before executing the code. If you specify a value of <code>0</code> (or omit the value), the function will run as soon as possible. (See the note below on why it runs "as soon as possible" and not "immediately".) More on why you might want to do this later.</li>
+ <li>Zero or more values that represent any parameters you want to pass to the function when it is run.</li>
+</ul>
+
+<div class="notecard note">
+<p><strong>NOTE:</strong> The specified amount of time (or the delay) is <strong>not</strong> the <em>guaranteed time</em> to execution, but rather the <em>minimum time</em> to execution. The callbacks you pass to these functions cannot run until the stack on the main thread is empty.</p>
+
+<p>As a consequence, code like <code>setTimeout(fn, 0)</code> will execute as soon as the stack is empty, <strong>not</strong> immediately. If you execute code like <code>setTimeout(fn, 0)</code> but then immediately after run a loop that counts from 1 to 10 billion, your callback will be executed after a few seconds.</p>
+</div>
+
+<p>In the following example, the browser will wait two seconds before executing the anonymous function, then will display the alert message (<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>The functions you specify don't have to be anonymous. You can give your function a name, and even define it somewhere else and pass a function reference to the <code>setTimeout()</code>. The following two versions of the code snippet are equivalent to the first one:</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>That can be useful if you have a function that needs to be called both from a timeout and in response to an event, for example. But it can also just help keep your code tidy, especially if the timeout callback is more than a few lines of code.</p>
+
+<p><code>setTimeout()</code> returns an identifier value that can be used to refer to the timeout later, such as when you want to stop it. See {{anch("Clearing timeouts")}} (below) to learn how to do that.</p>
+
+<h3 id="Passing_parameters_to_a_setTimeout_function">Passing parameters to a setTimeout() function</h3>
+
+<p>Any parameters that you want to pass to the function being run inside the <code>setTimeout()</code> must be passed to it as additional parameters at the end of the list.</p>
+
+<p>For example, you could refactor the previous function so that it will say hi to whatever person's name is passed to it:</p>
+
+<pre class="brush: js">function sayHi(who) {
+ alert(`Hello ${who}!`);
+}</pre>
+
+<p>Now, you can pass the name of the person into the <code>setTimeout()</code> call as a third parameter:</p>
+
+<pre class="brush: js">let myGreeting = setTimeout(sayHi, 2000, 'Mr. Universe');</pre>
+
+<h3 id="Clearing_timeouts">Clearing timeouts</h3>
+
+<p>Finally, if a timeout has been created, you can cancel it before the specified time has elapsed by calling <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearTimeout">clearTimeout()</a></code>, passing it the identifier of the <code>setTimeout()</code> call as a parameter. So to cancel our above timeout, you'd do this:</p>
+
+<pre class="brush: js">clearTimeout(myGreeting);</pre>
+
+<div class="notecard note">
+<p><strong>Note</strong>: See <code><a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/greeter-app.html">greeter-app.html</a></code> for a slightly more involved demo that allows you to set the name of the person to say hello to in a form, and cancel the greeting using a separate button (<a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/greeter-app.html">see the source code also</a>).</p>
+</div>
+
+<h2 id="setInterval">setInterval()</h2>
+
+<p><code>setTimeout()</code> works perfectly when you need to run code once after a set period of time. But what happens when you need to run the code over and over again—for example, in the case of an animation?</p>
+
+<p>This is where <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval">setInterval()</a></code> comes in. This works in a very similar way to <code>setTimeout()</code>, except that the function you pass as the first parameter is executed repeatedly at no less than the number of milliseconds given by the second parameter apart, rather than once. You can also pass any parameters required by the function being executed as subsequent parameters of the <code>setInterval()</code> call.</p>
+
+<p>Let's look at an example. The following function creates a new <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date">Date()</a></code> object, extracts a time string out of it using <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleTimeString">toLocaleTimeString()</a></code>, and then displays it in the UI. It then runs the function once per second using <code>setInterval()</code>, creating the effect of a digital clock that updates once per second (<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>Just like <code>setTimeout()</code>, <code>setInterval()</code> returns an identifying value you can use later when you need to clear the interval.</p>
+
+<h3 id="Clearing_intervals">Clearing intervals</h3>
+
+<p><code>setInterval()</code> keeps running a task forever, unless you do something about it. You'll probably want a way to stop such tasks, otherwise you may end up getting errors when the browser can't complete any further versions of the task, or if the animation being handled by the task has finished. You can do this the same way you stop timeouts — by passing the identifier returned by the <code>setInterval()</code> call to the <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearInterval">clearInterval()</a></code> function:</p>
+
+<pre class="brush: js">const myInterval = setInterval(myFunction, 2000);
+
+clearInterval(myInterval);</pre>
+
+<h4 id="Active_learning_Creating_your_own_stopwatch!">Active learning: Creating your own stopwatch!</h4>
+
+<p>With this all said, we've got a challenge for you. Take a copy of our <code><a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/setinterval-clock.html">setInterval-clock.html</a></code> example, and modify it to create your own simple stopwatch.</p>
+
+<p>You need to display a time as before, but in this example, you need:</p>
+
+<ul>
+ <li>A "Start" button to start the stopwatch running.</li>
+ <li>A "Stop" button to pause/stop it.</li>
+ <li>A "Reset" button to reset the time back to <code>0</code>.</li>
+ <li>The time display to show the number of seconds elapsed, rather than the actual time.</li>
+</ul>
+
+<p>Here's a few hints for you:</p>
+
+<ul>
+ <li>You can structure and style the button markup however you like; just make sure you use semantic HTML, with hooks to allow you to grab the button references using JavaScript.</li>
+ <li>You probably want to create a variable that starts at <code>0</code>, then increments by one every second using a constant loop.</li>
+ <li>It is easier to create this example without using a <code>Date()</code> object, like we've done in our version, but less accurate — you can't guarantee that the callback will fire after exactly <code>1000</code>ms. A more accurate way would be to run <code>startTime = Date.now()</code> to get a timestamp of exactly when the user clicked the start button, and then do <code>Date.now() - startTime</code> to get the number of milliseconds after the start button was clicked.</li>
+ <li>You also want to calculate the number of hours, minutes, and seconds as separate values, and then show them together in a string after each loop iteration. From the second counter, you can work out each of these.</li>
+ <li>How would you calculate them? Have a think about it:
+ <ul>
+ <li>The number of seconds in an hour is <code>3600</code>.</li>
+ <li>The number of minutes will be the amount of seconds left over when all of the hours have been removed, divided by <code>60</code>.</li>
+ <li>The number of seconds will be the amount of seconds left over when all of the minutes have been removed.</li>
+ </ul>
+ </li>
+ <li>You'll want to include a leading zero on your display values if the amount is less than <code>10</code>, so it looks more like a traditional clock/watch.</li>
+ <li>To pause the stopwatch, you'll want to clear the interval. To reset it, you'll want to set the counter back to <code>0</code>, clear the interval, and then immediately update the display.</li>
+ <li>You probably ought to disable the start button after pressing it once, and enable it again after you've stopped/reset it. Otherwise multiple presses of the start button will apply multiple <code>setInterval()</code>s to the clock, leading to wrong behavior.</li>
+</ul>
+
+<div class="notecard 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="Things_to_keep_in_mind_about_setTimeout_and_setInterval">Things to keep in mind about setTimeout() and setInterval()</h2>
+
+<p>There are a few things to keep in mind when working with <code>setTimeout()</code> and <code>setInterval()</code>. Let's review these now.</p>
+
+<h3 id="Recursive_timeouts">Recursive timeouts</h3>
+
+<p>There is another way to use <code>setTimeout()</code>: you can call it recursively to run the same code repeatedly, instead of using <code>setInterval()</code>.</p>
+
+<p>The below example uses a recursive <code>setTimeout()</code> to run the passed function every <code>100</code> milliseconds:</p>
+
+<pre class="brush: js">let i = 1;
+
+setTimeout(function run() {
+ console.log(i);
+ i++;
+ setTimeout(run, 100);
+}, 100);</pre>
+
+<p>Compare the above example to the following one — this uses <code>setInterval()</code> to accomplish the same effect:</p>
+
+<pre class="brush: js">let i = 1;
+
+setInterval(function run() {
+ console.log(i);
+ i++
+}, 100);</pre>
+
+<h4 id="How_do_recursive_setTimeout_and_setInterval_differ">How do recursive <code>setTimeout()</code> and <code>setInterval()</code> differ?</h4>
+
+<p>The difference between the two versions of the above code is a subtle one.</p>
+
+<ul>
+ <li>Recursive <code>setTimeout()</code> guarantees the given delay between the code execution completion and the next call. The delay for the next execution will start counting only after the code has finished running, therefore <em>excluding</em> the time taken to run the code. In this example, the <code>100</code> milliseconds will be the delay between the <code>run</code> code finishing, and the next <code>run</code> call.</li>
+ <li>The example using <code>setInterval()</code> does things somewhat differently. The interval you chose <em>includes</em> the time taken to execute the code you want to run in. Let's say that the code takes <code>40</code> milliseconds to run — the interval then ends up being only <code>60</code> milliseconds.</li>
+ <li>When using <code>setTimeout()</code> recursively, each iteration can calculate a different delay before running the next iteration. In other words, the value of the second parameter can specify a different time in milliseconds to wait before running the code again.</li>
+</ul>
+
+<p>When your code has the potential to take longer to run than the time interval you’ve assigned, it’s better to use recursive <code>setTimeout()</code> — this will keep the time interval constant between executions regardless of how long the code takes to execute, and you won't get errors.</p>
+
+<h3 id="Immediate_timeouts">Immediate timeouts</h3>
+
+<p>Using <code>0</code> as the value for <code>setTimeout()</code> schedules the execution of the specified callback function as soon as possible but only after the main code thread has been run.</p>
+
+<p>For instance, the code below (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/zero-settimeout.html">see it live</a>) outputs an alert containing <code>"Hello"</code>, then an alert containing <code>"World"</code> as soon as you click OK on the first alert.</p>
+
+<pre class="brush: js">setTimeout(function() {
+ alert('World');
+}, 0);
+
+alert('Hello');</pre>
+
+<p>This can be useful in cases where you want to set a block of code to run as soon as all of the main thread has finished running — put it on the async event loop, so it will run straight afterwards.</p>
+
+<h3 id="Clearing_with_clearTimeout_or_clearInterval">Clearing with clearTimeout() or clearInterval()</h3>
+
+<p><code>clearTimeout()</code> and <code>clearInterval()</code> both use the same list of entries to clear from. Interestingly enough, this means that you can use either method to clear a <code>setTimeout()</code> or <code>setInterval()</code>.</p>
+
+<p>For consistency, you should use <code>clearTimeout()</code> to clear <code>setTimeout()</code> entries and <code>clearInterval()</code> to clear <code>setInterval()</code> entries. This will help to avoid confusion.</p>
+
+<h2 id="requestAnimationFrame">requestAnimationFrame()</h2>
+
+<p><code><a href="/en-US/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame()</a></code> is a specialized looping function created for running animations efficiently in the browser. It is basically the modern version of <code>setInterval()</code> — it executes a specified block of code before the browser next repaints the display, allowing an animation to be run at a suitable frame rate regardless of the environment it is being run in.</p>
+
+<p>It was created in response to perceived problems with <code>setInterval()</code>, which for example doesn't run at a frame rate optimized for the device, sometimes drops frames, continues to run even if the tab is not the active tab or the animation is scrolled off the page, etc.</p>
+
+<p>(<a href="http://creativejs.com/resources/requestanimationframe/index.html">Read more about this on CreativeJS</a>.)</p>
+
+<div class="notecard note">
+<p><strong>Note</strong>: You can find examples of using <code>requestAnimationFrame()</code> elsewhere in the course — see for example <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Drawing graphics</a>, and <a href="/en-US/docs/Learn/JavaScript/Objects/Object_building_practice">Object building practice</a>.</p>
+</div>
+
+<p>The method takes as an argument a callback to be invoked before the repaint. This is the general pattern you'll see it used in:</p>
+
+<pre class="brush: js">function draw() {
+ // Drawing code goes here
+ requestAnimationFrame(draw);
+}
+
+draw();</pre>
+
+<p>The idea is to define a function in which your animation is updated (e.g. your sprites are moved, score is updated, data is refreshed, or whatever). Then, you call it to start the process off. At the end of the function block you call <code>requestAnimationFrame()</code> with the function reference passed as the parameter, and this instructs the browser to call the function again on the next display repaint. This is then run continuously, as the code is calling <code>requestAnimationFrame()</code> recursively.</p>
+
+<div class="notecard note">
+<p><strong>Note</strong>: If you want to perform some kind of simple constant DOM animation, <a href="/en-US/docs/Web/CSS/CSS_Animations">CSS Animations</a> are probably faster. They are calculated directly by the browser's internal code, rather than JavaScript.</p>
+
+<p>If, however, you are doing something more complex and involving objects that are not directly accessible inside the DOM (such as <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), <code>requestAnimationFrame()</code> is the better option in most cases.</p>
+</div>
+
+<h3 id="How_fast_does_your_animation_run">How fast does your animation run?</h3>
+
+<p>The smoothness of your animation is directly dependent on your animation's frame rate and it is measured in frames per second (fps). The higher this number is, the smoother your animation will look, to a point.</p>
+
+<p>Since most screens have a refresh rate of 60Hz, the fastest frame rate you can aim for is 60 frames per second (FPS) when working with web browsers. However, more frames means more processing, which can often cause stuttering and skipping — also known as <em>dropping frames</em>, or <em>jank</em>.</p>
+
+<p>If you have a monitor with a 60Hz refresh rate and you want to achieve 60 FPS you have about 16.7 milliseconds (<code>1000 / 60</code>) to execute your animation code to render each frame. This is a reminder that you'll need to be mindful of the amount of code that you try to run during each pass through the animation loop.</p>
+
+<p><code>requestAnimationFrame()</code> always tries to get as close to this magic 60 FPS value as possible. Sometimes, it isn't possible — if you have a really complex animation and you are running it on a slow computer, your frame rate will be less. In all cases, <code>requestAnimationFrame()</code> will always do the best it can with what it has available.</p>
+
+<h3 id="How_does_requestAnimationFrame_differ_from_setInterval_and_setTimeout">How does requestAnimationFrame() differ from setInterval() and setTimeout()?</h3>
+
+<p>Let's talk a little bit more about how the <code>requestAnimationFrame()</code> method differs from the other methods used earlier. Looking at our code from above:</p>
+
+<pre class="brush: js">function draw() {
+ // Drawing code goes here
+ requestAnimationFrame(draw);
+}
+
+draw();</pre>
+
+<p>Let's now see how to do the same thing using <code>setInterval()</code>:</p>
+
+<pre class="brush: js">function draw() {
+ // Drawing code goes here
+}
+
+setInterval(draw, 17);</pre>
+
+<p>As we covered earlier, you don't specify a time interval for <code>requestAnimationFrame()</code>. It just runs it as quickly and smoothly as possible in the current conditions. The browser also doesn't waste time running it if the animation is offscreen for some reason, etc.</p>
+
+<p><code>setInterval()</code>, on the other hand <em>requires</em> an interval to be specified. We arrived at our final value of 17 via the formula <em>1000 milliseconds / 60Hz</em>, and then rounded it up. Rounding up is a good idea; if you rounded down, the browser might try to run the animation faster than 60 FPS, and it wouldn't make any difference to the animation's smoothness, anyway. As we said before, 60Hz is the standard refresh rate.</p>
+
+<h3 id="Including_a_timestamp">Including a timestamp</h3>
+
+<p>The actual callback passed to the <code>requestAnimationFrame()</code> function can be given a parameter, too: a <em>timestamp</em> value, that represents the time since the <code>requestAnimationFrame()</code> started running.</p>
+
+<p>This is useful as it allows you to run things at specific times and at a constant pace, regardless of how fast or slow your device might be. The general pattern you'd use looks something like this:</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="Browser_support">Browser support</h3>
+
+<p><code>requestAnimationFrame()</code> is supported in more recent browsers than <code>setInterval()</code>/<code>setTimeout()</code>.  Interestingly, it is available in Internet Explorer 10 and above.</p>
+
+<p>So, unless you need to support older versions of IE, there is little reason to not use <code>requestAnimationFrame()</code>.</p>
+
+<h3 id="A_simple_example">A simple example</h3>
+
+<p>Enough with the theory! Let's build your own personal <code>requestAnimationFrame()</code> example. You're going to create a simple "spinner animation"—the kind you might see displayed in an app when it is busy connecting to the server, etc.</p>
+
+<div class="notecard note">
+<p><strong>Note</strong>: In a real world example, you should probably use CSS animations to run this kind of simple animation. However, this kind of example is very useful to demonstrate <code>requestAnimationFrame()</code> usage, and you'd be more likely to use this kind of technique when doing something more complex such as updating the display of a game on each frame.</p>
+</div>
+
+<ol>
+ <li>
+ <p>Grab a basic HTML template (<a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">such as this one</a>).</p>
+ </li>
+ <li>
+ <p>Put an empty {{htmlelement("div")}} element inside the {{htmlelement("body")}}, then add a ↻ character inside it. This circular arrow character will act as our spinner for this example.</p>
+ </li>
+ <li>
+ <p>Apply the following CSS to the HTML template (in whatever way you prefer). This sets a red background on the page, sets the <code>&lt;body&gt;</code> height to <code>100%</code> of the {{htmlelement("html")}} height, and centers the <code>&lt;div&gt;</code> inside the <code>&lt;body&gt;</code>, horizontally and vertically.</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>Insert a {{htmlelement("script")}} element just above the closing <code>&lt;/body&gt;</code> tag.</p>
+ </li>
+ <li>
+ <p>Insert the following JavaScript inside your <code>&lt;script&gt;</code> element. Here, you're storing a reference to the <code>&lt;div&gt;</code> inside a constant, setting a <code>rotateCount</code> variable to <code>0</code>, setting an uninitialized variable that will later be used to contain a reference to the <code>requestAnimationFrame()</code> call, and setting a <code>startTime</code> variable to <code>null</code>, which will later be used to store the start time of the <code>requestAnimationFrame()</code>.</p>
+
+ <pre class="brush: js">const spinner = document.querySelector('div');
+let rotateCount = 0;
+let startTime = null;
+let rAF;
+</pre>
+ </li>
+ <li>
+ <p>Below the previous code, insert a <code>draw()</code> function that will be used to contain our animation code, which includes the <code>timestamp</code> parameter:</p>
+
+ <pre class="brush: js">function draw(timestamp) {
+
+}</pre>
+ </li>
+ <li>
+ <p>Inside <code>draw()</code>, add the following lines. They will define the start time if it is not defined already (this will only happen on the first loop iteration), and set the <code>rotateCount</code> to a value to rotate the spinner by (the current timestamp, take the starting timestamp, divided by three so it doesn't go too fast):</p>
+
+ <pre class="brush: js"> if (!startTime) {
+ startTime = timestamp;
+ }
+
+ rotateCount = (timestamp - startTime) / 3;
+</pre>
+ </li>
+ <li>
+ <p>Below the previous line inside <code>draw()</code>, add the following block — this ensures that the value of <code>rotateCount</code> is between <code>0</code> and <code>359</code>, by setting the value to its modulo of <code>360</code> (i.e. the remainder left over when the value is divided by <code>360</code>) — so the circle animation can continue uninterrupted, at a sensible, low value. Note that this isn't strictly necessary, but it is easier to work with values of <code>0</code>–<code>359</code> degrees than values like <code>"128000 degrees"</code>.</p>
+
+ <pre class="brush: js"> rotateCount %= 360; </pre>
+ </li>
+ <li>Next, below the previous block add the following line to actually rotate the spinner:
+ <pre class="brush: js">spinner.style.transform = `rotate(${rotateCount}deg)`;</pre>
+ </li>
+ <li>
+ <p>At the very bottom inside the <code>draw()</code> function, insert the following line. This is the key to the whole operation — you are setting the variable defined earlier to an active <code>requestAnimation()</code> call, which takes the <code>draw()</code> function as its parameter. This starts the animation off, constantly running the <code>draw()</code> function at a rate as near 60 FPS as possible.</p>
+
+ <pre class="brush: js">rAF = requestAnimationFrame(draw);</pre>
+ </li>
+ <li>
+ <p>Below the <code>draw()</code> function definition, add a call to the <code>draw()</code> function to start the animation.</p>
+
+ <pre class="brush: js">draw();</pre>
+ </li>
+</ol>
+
+<div class="notecard note">
+<p><strong>Note</strong>: You can find the finished <a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/simple-raf-spinner.html">example live on GitHub</a>. (You can 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="Clearing_a_requestAnimationFrame_call">Clearing a requestAnimationFrame() call</h3>
+
+<p>Clearing a <code>requestAnimationFrame()</code> call can be done by calling the corresponding <code>cancelAnimationFrame()</code> method. (Note that the function name starts with "cancel", not "clear" as with the "set..." methods.) </p>
+
+<p>Just pass it the value returned by the <code>requestAnimationFrame()</code> call to cancel, which you stored in the variable <code>rAF</code>:</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="notecard 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, you 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 you 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. This example therefore throttles 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 the code only cycles the sprite once every 13 animation frames.</p>
+
+<p>...Actually, it's 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 calculates 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 instance, in the earlier spinner example, you could make it appear to move slower by only increasing <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 the final section of this article, you'll create a 2-player reaction game. The game will 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 <code>"PLAYERS GO!!"</code> — 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. You 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 you'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 the spinner, so you 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. This determines how much you want to show the spinner rotated on each frame of the animation.</li>
+ <li>A null start time. This 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. It takes two numbers and returns a random number between the two. You'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  the <code>draw()</code> function, which animates the spinner. This is very similar to the version from the simple spinner example, earlier:</p>
+
+ <pre class="brush: js">function draw(timestamp) {
+ if(!startTime) {
+ startTime = timestamp;
+ }
+
+ rotateCount = (timestamp - startTime) / 3;
+
+ 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 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>Next, 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>Okay, enough preparation!  It's time to 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 you 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. The following block also adds an event listener to your 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="notecard note">
+ <p><strong>Note</strong>: You'll see this example is calling <code>setTimeout()</code> without storing the return value. (So, not <code>let myTimeout = setTimeout(functionName, interval)</code>.) </p>
+
+ <p>This works just 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 asked to press their button. This last part is handled by the <code>setEndgame()</code> function, which you'll define next.</p>
+ </li>
+ <li>
+ <p>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) {
+ let isOver = false;
+ console.log(e.key);
+
+ if (e.key === "a") {
+ result.textContent = 'Player 1 won!!';
+ isOver = true;
+ } else if (e.key === "l") {
+ result.textContent = 'Player 2 won!!';
+ isOver = true;
+ }
+
+ if (isOver) {
+ document.removeEventListener('keydown', keyHandler);
+ setTimeout(reset, 5000);
+ }
+ };
+}</pre>
+
+ <p>Stepping through this:</p>
+
+ <ol>
+ <li>First, 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, 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>Attach a <code><a href="/en-US/docs/Web/API/Document/keydown_event">keydown</a></code> event listener to the document. When any button is pressed down, the <code>keyHandler()</code> function is run.</li>
+ <li>Inside <code>keyHandler()</code>, the code includes 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 you can use this to respond to specific key presses with specific actions.</li>
+ <li>Set the variable <code>isOver</code> to false, so we can track whether the correct keys were pressed for player 1 or 2 to win. We don't want the game ending when a wrong key was pressed.</li>
+ <li>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", display a message to say that Player 1 won, and when <code>e.key</code> is "l", display a message to say Player 2 won. (<strong>Note:</strong> 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!) If one of these keys was pressed, set <code>isOver</code> to <code>true</code>.</li>
+ <li>Only if <code>isOver</code> is <code>true</code>, 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. You also use <code>setTimeout()</code> to call <code>reset()</code> after 5 seconds — as 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="notecard 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! Because they 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>
+
+<div id="gtx-trans" style="position: absolute; left: 70px; top: 13746px;">
+<div class="gtx-trans-icon"></div>
+</div>