diff options
Diffstat (limited to 'files/zh-tw/web/javascript/reference/global_objects/promise/index.html')
-rw-r--r-- | files/zh-tw/web/javascript/reference/global_objects/promise/index.html | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/files/zh-tw/web/javascript/reference/global_objects/promise/index.html b/files/zh-tw/web/javascript/reference/global_objects/promise/index.html new file mode 100644 index 0000000000..8ec1456ae1 --- /dev/null +++ b/files/zh-tw/web/javascript/reference/global_objects/promise/index.html @@ -0,0 +1,256 @@ +--- +title: Promise +slug: Web/JavaScript/Reference/Global_Objects/Promise +translation_of: Web/JavaScript/Reference/Global_Objects/Promise +--- +<div>{{JSRef}}</div> + +<p><strong><code>Promise</code></strong> 物件代表一個即將完成、或失敗的非同步操作,以及它所產生的值。</p> + +<div class="note"> +<p>此條目為介紹 Promise 建構式。要瞭解 Promise 相關使用方式,請先參考<a href="/zh-TW/docs/Web/JavaScript/Guide/Using_promises">使用 Promise</a>。Promise 建構式主要用於包裹尚未支援 Promise 的函式。</p> +</div> + +<div>{{EmbedInteractiveExample("pages/js/promise-constructor.html")}}</div> + + + +<p class="hidden">The source for this interactive demo is stored in a GitHub repository. If you'd like to contribute to the interactive demo project, please clone <a href="https://github.com/mdn/interactive-examples">https://github.com/mdn/interactive-examples</a> and send us a pull request.</p> + +<h2 id="語法">語法</h2> + +<pre class="brush: js">new Promise( /* executor */ function(resolve, reject) { ... } );</pre> + +<h3 id="參數">參數</h3> + +<dl> + <dt>executor</dt> + <dd>為一個依序接收兩個參數的函式:<code>resolve</code> 及 <code>reject</code>(實現及拒絕回呼函式)。在 Promise 實作中,<code>executor</code> 函式在傳入參數 <code>resolve</code> 與 <code>reject</code> 後會立刻執行(<code>executor</code> 函式會在 <code>Promise</code> 建構式回傳 Promise 物件前被執行)。<code>resolve</code> 與 <code>reject</code> 函式,會在被個別呼叫時,個別執行之。通常 executor 函式會發起一些非同步操作。接著,成功完成後執行 <code>resolve</code> 以完成 promise;或如果有錯誤,執行 <code>rejects</code>。<br>如果 executor 函式在執行中拋出錯誤,promise 會被拒絕(rejected),回傳值也將被忽略。</dd> +</dl> + +<h2 id="描述">描述</h2> + +<p><code><strong>Promise</strong></code> 會代理一個建立時,不用預先得知的值。它使你能夠繫結(associate)著發動非同步操作後,最終的成功值(success value)或失敗訊息(failure reason)的處理函式(handlers)。這讓非同步方法回傳值的方式很像同步方法,但不是回傳最終結果:非同步方法回傳一個 <em>promise</em> 物件作為未來某時間點的值。</p> + +<p>一個 <code>Promise</code> 物件處於以下幾種狀態:</p> + +<ul> + <li><em>擱置(pending)</em>:初始狀態,不是 fulfilled 與 rejected。</li> + <li><em>實現(fulfilled)</em>:表示操作成功地完成。</li> + <li><em>拒絕(rejected)</em>:表示操作失敗了。</li> +</ul> + +<p>一個處於擱置狀態的 promise 能以一個值被實現(fulfilled),或是以一個原因或錯誤而被拒絕(rejected)。當上述任一狀態轉換發生時,那些透過 <code>then</code> 方法所繫結(associated)的處理函式列隊就會依序被調用。(若一個 promise 已被實現或拒絕,繫結(attached)於它的處理函式將立即被呼叫,因此完成非同步操作與繫結處理函式之間不存在競爭條件(race condition)。)</p> + +<p>由於 <code>{{jsxref("Promise.then", "Promise.prototype.then()")}}</code> 以及 <code>{{jsxref("Promise.catch", "Promise.prototype.catch()")}}</code> 方法都回傳 promise,它們可以被串接。</p> + +<p><img alt="" src="https://cdn.rawgit.com/Vectaio/a76330b025baf9bcdf07cb46e5a9ef9e/raw/26c4213a93dee1c39611dcd0ec12625811b20a26/js-promise.svg"></p> + +<div class="note"> +<p><strong>容易混淆:</strong> 許多其他語言擁有機制用來惰性求值(lazy evaluation)及延遲(deferring)運算,它們也被稱作“promises” — e.g. Scheme. 然而在 JavaScript 中 Promises 代表那些(已經)發生中(happening)的程序,它們可以繫結回呼函式。若您要找的是惰性求值表示式,考慮不帶參數的 <a href="/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions">arrow function</a>:<code>f = () => <em>expression</em></code> 來建立惰性求值表示式,並透過 <code>f()</code> 進行求值.</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: 一個被實現或拒絕,但不處於 pending 的 promise 被稱作被解決(settled)。您也會見到使用解決(resolved)一詞來描述 promises — 這代表 promises 被實現(fulfilled)了。<a href="https://github.com/domenic/promises-unwrapping/blob/master/docs/states-and-fates.md">States and fates</a> 這篇文章包含了更多 promises 的專有名詞。</p> +</div> + +<h2 id="屬性">屬性</h2> + +<dl> + <dt><code>Promise.length</code></dt> + <dd>長度屬性,值固定為 <code>1</code>。(建構式參數數目).</dd> + <dt>{{jsxref("Promise.prototype")}}</dt> + <dd><code>Promise</code> 建構式的原型(prototype).</dd> +</dl> + +<h2 id="方法">方法</h2> + +<dl> + <dt>{{jsxref("Promise.all", "Promise.all(iterable)")}}</dt> + <dd>回傳一個 promise,當在引數 iterable 中所有 promises 都被實現時被實現,或在引數 iterable 中有一個 promise 被拒絕時立刻被拒絕。若回傳的 promise 被實現,它將以一個實現值的陣列被實現,其順序與 iterable 中的 promises 相同。若回傳的 promise 被拒絕,它將以失敗訊息被拒絕,此訊息來自第一個在 iterable 中被拒絕的 promise。這個方法在聚集許多 promises 的結果時很有效。</dd> + <dt>{{jsxref("Promise.race", "Promise.race(iterable)")}}</dt> + <dd>回傳一個被實現或拒絕的 promise,當 iterable 中有一個 promise 被實現或拒絕時。</dd> +</dl> + +<dl> + <dt>{{jsxref("Promise.reject", "Promise.reject(reason)")}}</dt> + <dd>回傳一個以失敗訊息拒絕的 <code>promise</code>。</dd> +</dl> + +<dl> + <dt>{{jsxref("Promise.resolve", "Promise.resolve(value)")}}</dt> + <dd>回傳一個以 value 實現的 <code>promise</code>。若該值為 thenable (i.e. 具有 <code>then</code> 方法),回傳的 promise 將跟隨(follow)之,採用她的最終狀態; 在其他情形回傳的 promise 將以 value 被實現。一般來說,當您不知道 value 是否為 promise,使用 {{jsxref("Promise.resolve", "Promise.resolve(value)")}},將回傳值以 promise 作處理。</dd> +</dl> + +<h2 id="Promise_原型"><code>Promise</code> 原型</h2> + +<h3 id="屬性_2">屬性</h3> + +<p>{{page('zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Promise/prototype','屬性')}}</p> + +<h3 id="方法_2">方法</h3> + +<p>{{page('zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Promise/prototype','方法')}}</p> + +<h2 id="建立_Promise">建立 Promise</h2> + +<p><code><font face="Open Sans, arial, x-locale-body, sans-serif">一個</font></code> <code>Promise</code> 物件透過 <code>new</code> 及其建構式建立。這個建構式接收一個叫作”執行器函式(executor function)“的引數。此函式接收兩個函式作為引數。第一個函式(<code>resolve)</code>在非同步作業成功完成時,以該作業之結果值被呼叫。第二個函式(<code>reject</code>)在作業失敗時,以失敗訊息,通常是一個 error object,被呼叫。</p> + +<pre class="brush: js">const myFirstPromise = new Promise((resolve, reject) => { + // 執行一些非同步作業,最終呼叫: + // + // resolve(someValue); // 實現 + // 或 + // reject("failure reason"); // 拒絕 +}); +</pre> + +<p>要提供一個函式 promise 功能,讓它回傳一個 promise 即可:</p> + +<pre class="brush: js">function myAsyncFunction(url) { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.open("GET", url); + xhr.onload = () => resolve(xhr.responseText); + xhr.onerror = () => reject(xhr.statusText); + xhr.send(); + }); +};</pre> + +<h2 id="範例">範例</h2> + +<h3 id="入門範例">入門範例</h3> + +<pre class="brush: js">let myFirstPromise = new Promise((resolve, reject) => { + // 當非同步作業成功時,呼叫 resolve(...),而失敗時則呼叫 reject(...)。 + // 在這個例子中,使用 setTimeout(...) 來模擬非同步程式碼。 + // 在實務中,您將可能使用像是 XHR 或者一個 HTML5 API. + setTimeout(function(){ + resolve("Success!"); // Yay!非常順利! + }, 250); +}); + +myFirstPromise.then((successMessage) => { + // successMessage 是任何您由上方 resolve(...) 傳入的東西。 + // 在此僅作為成功訊息,但是它不一定是字串。 + console.log("Yay! " + successMessage); +}); +</pre> + +<h3 id="進階範例">進階範例</h3> + +<pre class="brush: html hidden"><button id="btn">Make a promise!</button> +<div id="log"></div> +</pre> + +<p><code>這個小範例演示了</code> <code>Promise</code> <code>的運作機制。每當 </code>{{HTMLElement("button")}} 被點擊時,<code>testPromise()</code> 方法被呼叫。每次點擊將透過 {{domxref("window.setTimeout()")}} 建立一個將在 1-3 秒內隨機地被實現的 promise,供 promise 計數(一個從 1 開始的數值)。建構式 <code>Promise()</code> 被用來建立 promise。</p> + +<p>promise 的實現值單純地經由一個實現回呼函式 {{jsxref("Promise.prototype.then()","p1.then()")}} 被印出。下以一些文字紀錄來展現方法中同步的與非同步處理 promise 的部分是如何分離彼此。</p> + +<pre class="brush: js">'use strict'; +var promiseCount = 0; + +function testPromise() { + let thisPromiseCount = ++promiseCount; + + let log = document.getElementById('log'); + log.insertAdjacentHTML('beforeend', thisPromiseCount + + ') Started (<small>Sync code started</small>)<br/>'); + + // 建立一個新的 promise:此 promise 承諾一個數值計數, 由 1 開始(等待約 2 秒) + let p1 = new Promise( + // 這個解決器函數(resolver function)呼叫實現或 + // 拒絕 promise。 + (resolve, reject) => { + log.insertAdjacentHTML('beforeend', thisPromiseCount + + ') Promise started (<small>Async code started</small>)<br/>'); + // 在此例子單純用來產生非同步特性。 + window.setTimeout( + function() { + // 實現這個 promise! + resolve(thisPromiseCount); + }, Math.random() * 2000 + 1000); + } + ); + + // 接著透過呼叫 then() 來決定 promise 進入 resolved 時,要透過 then() 做什麼, + // 或是進入 rejected 時,要透過 catch() 方法要做什麼。 + p1.then( + // 印出實現值(fulfillment value) + function(val) { + log.insertAdjacentHTML('beforeend', val + + ') Promise fulfilled (<small>Async code terminated</small>)<br/>'); + }) + .catch( + // 印出失敗訊息(rejection reason) + (reason) => { + console.log('Handle rejected promise ('+reason+') here.'); + }); + + log.insertAdjacentHTML('beforeend', thisPromiseCount + + ') Promise made (<small>Sync code terminated</small>)<br/>'); +}</pre> + +<p><sub>*譯註:resolver function 即 executor function。</sub></p> + +<pre class="brush:js hidden">if ("Promise" in window) { + let btn = document.getElementById("btn"); + btn.addEventListener("click",testPromise); +} else { + log = document.getElementById('log'); + log.innerHTML = "Live example not available as your browser doesn't support the <code>Promise<code> interface."; +} +</pre> + +<p>這個範例從點擊按鈕開始。您的瀏覽器需要支援 Promise。在短時間內點擊按鈕許多次,您甚至將看到不同的 promises 一個接一個地被實現。</p> + +<p>{{EmbedLiveSample("Advanced_Example", "500", "200")}}</p> + +<h2 id="使用_XHR_載入圖片">使用 XHR 載入圖片</h2> + +<p>另一個使用 <code>Promise</code> and <code><a href="/zh-TW/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a></code> 來載入圖片的簡單例子可以在 MDN GitHub <a href="https://github.com/mdn/js-examples/tree/master/promises-test">js-examples</a> 儲存庫找到。 你也可以<a href="https://mdn.github.io/js-examples/promises-test/">see it in action</a>。每個步驟都附以註解,讓你能逐步遵隨 Promise 與 XHR 架構。</p> + +<h2 id="規範">規範</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">Specification</th> + <th scope="col">Status</th> + <th scope="col">Comment</th> + </tr> + <tr> + <td>{{SpecName('ES2015', '#sec-promise-objects', 'Promise')}}</td> + <td>{{Spec2('ES2015')}}</td> + <td>Initial definition in an ECMA standard.</td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-promise-objects', 'Promise')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td> </td> + </tr> + </tbody> +</table> + +<h2 id="瀏覽器相容性">瀏覽器相容性</h2> + +<p class="hidden">To contribute to this compatibility data, please write a pull request against this repository: <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a>.</p> + +<p>{{Compat("javascript.builtins.Promise")}}</p> + +<h2 id="參見">參見</h2> + +<ul> + <li><a href="/zh-TW/docs/Web/JavaScript/Guide/Using_promises">Using promises</a></li> + <li><a href="http://promisesaplus.com/">Promises/A+ specification</a></li> + <li><a href="https://medium.com/@ramsunvtech/promises-of-promise-part-1-53f769245a53">Venkatraman.R - JS Promise (Part 1, Basics)</a></li> + <li><a href="https://medium.com/@ramsunvtech/js-promise-part-2-q-js-when-js-and-rsvp-js-af596232525c#.dzlqh6ski">Venkatraman.R - JS Promise (Part 2 - Using Q.js, When.js and RSVP.js)</a></li> + <li><a href="https://tech.io/playgrounds/11107/tools-for-promises-unittesting/introduction">Venkatraman.R - Tools for Promises Unit Testing</a></li> + <li><a href="http://www.html5rocks.com/en/tutorials/es6/promises/">Jake Archibald: JavaScript Promises: There and Back Again</a></li> + <li><a href="http://de.slideshare.net/domenicdenicola/callbacks-promises-and-coroutines-oh-my-the-evolution-of-asynchronicity-in-javascript">Domenic Denicola: Callbacks, Promises, and Coroutines – Asynchronous Programming Patterns in JavaScript</a></li> + <li><a href="http://www.mattgreer.org/articles/promises-in-wicked-detail/">Matt Greer: JavaScript Promises ... In Wicked Detail</a></li> + <li><a href="https://www.promisejs.org/">Forbes Lindesay: promisejs.org</a></li> + <li><a href="http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html">Nolan Lawson: We have a problem with promises — Common mistakes with promises</a></li> + <li><a href="https://github.com/jakearchibald/es6-promise/">Promise polyfill</a></li> + <li><a href="https://www.udacity.com/course/javascript-promises--ud898">Udacity: JavaScript Promises</a></li> +</ul> |