diff options
Diffstat (limited to 'files/zh-cn/web/javascript/reference/global_objects/promise')
12 files changed, 1884 insertions, 0 deletions
diff --git a/files/zh-cn/web/javascript/reference/global_objects/promise/all/index.html b/files/zh-cn/web/javascript/reference/global_objects/promise/all/index.html new file mode 100644 index 0000000000..84264ce68b --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/promise/all/index.html @@ -0,0 +1,224 @@ +--- +title: Promise.all() +slug: Web/JavaScript/Reference/Global_Objects/Promise/all +tags: + - AJAX + - Async-Await + - Fetch + - Promise + - Promise.all() + - Promise.race() + - promise.all +translation_of: Web/JavaScript/Reference/Global_Objects/Promise/all +--- +<div>{{JSRef}}</div> + +<p><code><strong>Promise.all(iterable)</strong></code> 方法返回一个 {{jsxref("Promise")}} 实例,此实例在 <code>iterable</code> 参数内所有的 <code>promise</code> 都“完成(resolved)”或参数中不包含 <code>promise</code> 时回调完成(resolve);如果参数中 <code>promise</code> 有一个失败(rejected),此实例回调失败(reject),失败的原因是第一个失败 <code>promise</code> 的结果。</p> + +<p>它通常在启动多个异步任务并发运行并为其结果创建承诺之后使用,以便人们可以等待所有任务完成。</p> + +<div>{{EmbedInteractiveExample("pages/js/promise-all.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="syntaxbox"><var>Promise.all(iterable)</var>;</pre> + +<h3 id="参数">参数</h3> + +<dl> + <dt>iterable</dt> + <dd>一个<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterable_protocol">可迭代</a>对象,如 {{jsxref("Array")}} 或 {{jsxref("String")}}。</dd> +</dl> + +<h3 id="返回值">返回值</h3> + +<ul> + <li>如果传入的参数是一个空的可迭代对象,则返回一个<strong>已完成(already resolved)</strong>状态的 {{jsxref("Promise")}}。</li> + <li>如果传入的参数不包含任何 <code>promise</code>,则返回一个<strong>异步完成(asynchronously resolved)</strong> {{jsxref("Promise")}}。注意:Google Chrome 58 在这种情况下返回一个<strong>已完成(already resolved)</strong>状态的 {{jsxref("Promise")}}。</li> + <li>其它情况下返回一个<strong>处理中(pending)</strong>的{{jsxref("Promise")}}。这个返回的 <code>promise</code> 之后会在所有的 <code>promise</code> 都完成或有一个 <code>promise</code> 失败时<strong>异步</strong>地变为完成或失败。 见下方关于“Promise.all 的异步或同步”示例。返回值将会按照参数内的 <code>promise</code> 顺序排列,而不是由调用 <code>promise</code> 的完成顺序决定。</li> +</ul> + +<h2 id="说明">说明</h2> + +<p>此方法在集合多个 <code>promise</code> 的返回结果时很有用。</p> + +<p>完成(Fulfillment):<br> + 如果传入的可迭代对象为空,<code>Promise.all</code> 会同步地返回一个已完成(resolved)状态的<code>promise</code>。<br> + 如果所有传入的 <code>promise</code> 都变为完成状态,或者传入的可迭代对象内没有 <code>promise</code>,<code>Promise.all</code> 返回的 <code>promise</code> 异步地变为完成。<br> + 在任何情况下,<code>Promise.all</code> 返回的 <code>promise</code> 的完成状态的结果都是一个数组,它包含所有的传入迭代参数对象的值(也包括非 <code>promise</code> 值)。</p> + +<p>失败/拒绝(Rejection):<br> + 如果传入的 <code>promise</code> 中有一个失败(rejected),<code>Promise.all</code> 异步地将失败的那个结果给失败状态的回调函数,而不管其它 <code>promise</code> 是否完成。</p> + +<h2 id="示例">示例</h2> + +<h3 id="Promise.all_的使用"><code>Promise.all</code> 的使用</h3> + +<p><code>Promise.all</code> 等待所有都完成(或第一个失败)。</p> + +<pre class="brush: js">var p1 = Promise.resolve(3); +var p2 = 1337; +var p3 = new Promise((resolve, reject) => { + setTimeout(resolve, 100, 'foo'); +}); + +Promise.all([p1, p2, p3]).then(values => { + console.log(values); // [3, 1337, "foo"] +});</pre> + +<p>如果参数中包含非 <code>promise</code> 值,这些值将被忽略,但仍然会被放在返回数组中(如果 <code>promise</code> 完成的话):</p> + +<pre class="brush: js">// this will be counted as if the iterable passed is empty, so it gets fulfilled +var p = Promise.all([1,2,3]); +// this will be counted as if the iterable passed contains only the resolved promise with value "444", so it gets fulfilled +var p2 = Promise.all([1,2,3, Promise.resolve(444)]); +// this will be counted as if the iterable passed contains only the rejected promise with value "555", so it gets rejected +var p3 = Promise.all([1,2,3, Promise.reject(555)]); + +// using setTimeout we can execute code after the stack is empty +setTimeout(function(){ + console.log(p); + console.log(p2); + console.log(p3); +}); + +// logs +// Promise { <state>: "fulfilled", <value>: Array[3] } +// Promise { <state>: "fulfilled", <value>: Array[4] } +// Promise { <state>: "rejected", <reason>: 555 }</pre> + +<h3 id="Promise.all_的异步和同步"><code>Promise.all</code> 的异步和同步</h3> + +<p>下面的例子中演示了 <code>Promise.all</code> 的异步性(如果传入的可迭代对象是空的,就是同步):</p> + +<pre class="brush: js">// we are passing as argument an array of promises that are already resolved, +// to trigger Promise.all as soon as possible +var resolvedPromisesArray = [Promise.resolve(33), Promise.resolve(44)]; + +var p = Promise.all(resolvedPromisesArray); +// immediately logging the value of p +console.log(p); + +// using setTimeout we can execute code after the stack is empty +setTimeout(function(){ + console.log('the stack is now empty'); + console.log(p); +}); + +// logs, in order: +// Promise { <state>: "pending" } +// the stack is now empty +// Promise { <state>: "fulfilled", <value>: Array[2] } +</pre> + +<p>如果 <code>Promise.all</code> 失败,也是一样的:</p> + +<pre class="brush: js">var mixedPromisesArray = [Promise.resolve(33), Promise.reject(44)]; +var p = Promise.all(mixedPromisesArray); +console.log(p); +setTimeout(function(){ + console.log('the stack is now empty'); + console.log(p); +}); + +// logs +// Promise { <state>: "pending" } +// the stack is now empty +// Promise { <state>: "rejected", <reason>: 44 } +</pre> + +<p>但是,<code>Promise.all</code> <strong>当且仅当</strong>传入的可迭代对象为空时为同步:</p> + +<pre class="brush: js">var p = Promise.all([]); // will be immediately resolved +var p2 = Promise.all([1337, "hi"]); // non-promise values will be ignored, but the evaluation will be done asynchronously +console.log(p); +console.log(p2) +setTimeout(function(){ + console.log('the stack is now empty'); + console.log(p2); +}); + +// logs +// Promise { <state>: "fulfilled", <value>: Array[0] } +// Promise { <state>: "pending" } +// the stack is now empty +// Promise { <state>: "fulfilled", <value>: Array[2] } +</pre> + +<h3 id="Promise.all_的快速返回失败行为"><code>Promise.all</code> 的快速返回失败行为</h3> + +<p><code>Promise.all</code> 在任意一个传入的 <code>promise</code> 失败时返回失败。例如,如果你传入的 <code>promise</code>中,有四个 <code>promise</code> 在一定的时间之后调用成功函数,有一个立即调用失败函数,那么 <code>Promise.all</code> 将立即变为失败。</p> + +<pre class="brush: js">var p1 = new Promise((resolve, reject) => { + setTimeout(resolve, 1000, 'one'); +}); +var p2 = new Promise((resolve, reject) => { + setTimeout(resolve, 2000, 'two'); +}); +var p3 = new Promise((resolve, reject) => { + setTimeout(resolve, 3000, 'three'); +}); +var p4 = new Promise((resolve, reject) => { + setTimeout(resolve, 4000, 'four'); +}); +var p5 = new Promise((resolve, reject) => { + reject('reject'); +}); + +Promise.all([p1, p2, p3, p4, p5]).then(values => { + console.log(values); +}, reason => { + console.log(reason) +}); + +//From console: +//"reject" + +//You can also use .catch +Promise.all([p1, p2, p3, p4, p5]).then(values => { + console.log(values); +}).catch(reason => { + console.log(reason) +}); + +//From console: +//"reject" + +</pre> + +<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.all', 'Promise.all')}}</td> + <td>{{Spec2('ES2015')}}</td> + <td>Initial definition in an ECMA standard.</td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-promise.all', 'Promise.all')}}</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.all")}}</p> + +<h2 id="参见">参见</h2> + +<ul> + <li>{{jsxref("Promise")}}</li> + <li>{{jsxref("Promise.race()")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/global_objects/promise/allsettled/index.html b/files/zh-cn/web/javascript/reference/global_objects/promise/allsettled/index.html new file mode 100644 index 0000000000..de674edc7f --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/promise/allsettled/index.html @@ -0,0 +1,73 @@ +--- +title: Promise.allSettled() +slug: Web/JavaScript/Reference/Global_Objects/Promise/allSettled +tags: + - Promise + - Promise.allSettled + - promise.all +translation_of: Web/JavaScript/Reference/Global_Objects/Promise/allSettled +--- +<p>{{JSRef}}</p> + +<p>该<code><strong>Promise.allSettled()</strong></code>方法返回一个在所有给定的promise都已经<code>fulfilled</code>或<code>rejected</code>后的promise,并带有一个对象数组,每个对象表示对应的promise结果。</p> + +<p>当您有多个彼此不依赖的异步任务成功完成时,或者您总是想知道每个<code>promise</code>的结果时,通常使用它。</p> + +<p><font><font>相比之下,</font></font><code><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/all">Promise.all()</a></code><font><font> 更适合彼此相互依赖或者在其中任何一个<code>reject</code>时立即结束。</font></font></p> + +<div>{{EmbedInteractiveExample("pages/js/promise-allsettled.html")}}</div> + +<h2 id="句法">句法</h2> + +<pre class="notranslate"><em>Promise</em>.allSettled(<em>iterable</em>);</pre> + +<h3 id="参数">参数</h3> + +<dl> + <dt><code>iterable</code></dt> + <dd>一个<a href="/zh-CN/docs/Web/JavaScript/Guide/iterable">可迭代的</a>对象,例如{{jsxref("Array")}},其中每个成员都是<code>Promise</code>。</dd> +</dl> + +<h3 id="返回值">返回值</h3> + +<p>一旦所指定的 promises 集合中每一个 promise 已经完成,无论是成功的达成或被拒绝,<strong>未决议的</strong> {{jsxref("Promise")}}将被<strong>异步</strong>完成。那时,所返回的 promise 的处理器将传入一个数组作为输入,该数组包含原始 promises 集中每个 promise 的结果。</p> + +<p>对于每个结果对象,都有一个 <code>status</code> 字符串。如果它的值为 <code>fulfilled</code>,则结果对象上存在一个 <code>value</code> 。如果值为 <code>rejected</code>,则存在一个 <code>reason</code> 。value(或 reason )反映了每个 promise 决议(或拒绝)的值。</p> + +<h2 id="标准">标准</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">规格</th> + <th scope="col">状态</th> + <th scope="col">评论</th> + </tr> + <tr> + <td><a href="https://tc39.es/proposal-promise-allSettled/"><code>Promise.allSettled()</code> (TC39第4阶段草案)</a></td> + <td>{{SPEC2("ESDraft")}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容">浏览器兼容</h2> + +<p>{{Compat("javascript.builtins.Promise.allSettled")}}</p> + +<h3 id="实现进度">实现进度</h3> + +<p>{{EmbedTest262ReportResultsTable("Promise.allSettled")}}</p> + +<h2 id="参见">参见</h2> + +<ul> + <li> +<a href="https://wiki.developer.mozilla.org/zh-CN/docs/Archive/Add-ons/Techniques/Promises">Promises</a></li> + <li> +<a href="https://wiki.developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises">Using promises</a></li> + <li> +<a href="https://wiki.developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Asynchronous/Promises">Graceful asynchronous programming with promises</a></li> + <li>{{jsxref("Promise")}}</li> + <li>{{jsxref("Promise.all()")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/global_objects/promise/any/index.html b/files/zh-cn/web/javascript/reference/global_objects/promise/any/index.html new file mode 100644 index 0000000000..25e87a91af --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/promise/any/index.html @@ -0,0 +1,153 @@ +--- +title: Promise.any() +slug: Web/JavaScript/Reference/Global_Objects/Promise/any +tags: + - Experimental + - JavaScript + - Method + - Promise + - Reference +translation_of: Web/JavaScript/Reference/Global_Objects/Promise/any +--- +<p>{{JSRef}}</p> + +<p><code>Promise.any()</code> 接收一个{{JSxRef("Promise")}}可迭代对象,只要其中的一个 <code>promise</code> 成功,就返回那个已经成功的 <code>promise</code> 。如果可迭代对象中没有一个 <code>promise</code> 成功(即所有的 <code>promises</code> 都失败/拒绝),就返回一个失败的 <code>promise </code>和{{JSxRef("Global_Objects/AggregateError", "AggregateError")}}类型的实例,它是 {{JSxRef("Error")}} 的一个子类,用于把单一的错误集合在一起。本质上,这个方法和{{JSxRef("Promise.all()")}}是相反的。</p> + +<div class="blockIndicator warning"> +<p><strong>注意!</strong> <code>Promise.any()</code> 方法依然是实验性的,尚未被所有的浏览器完全支持。它当前处于 <a href="https://github.com/tc39/proposal-promise-any">TC39 第四阶段草案(Stage 4)</a></p> +</div> + +<h2 id="语法">语法</h2> + +<pre class="notranslate">Promise.any(<var>iterable</var>);</pre> + +<h3 id="参数">参数</h3> + +<dl> + <dt><code>iterable</code></dt> + <dd>一个<a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterable_protocol">可迭代</a>的对象, 例如 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array">Array</a>。</dd> +</dl> + +<h3 id="返回值">返回值</h3> + +<ul> + <li>如果传入的参数是一个空的可迭代对象,则返回一个 <strong>已失败(already rejected)</strong> 状态的 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise</a>。</li> + <li>如果传入的参数不包含任何 <code>promise</code><var>,则返回</var>一个 <strong>异步完成</strong> (<strong>asynchronously resolved</strong>)的 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise</a>。</li> + <li>其他情况下都会返回一个<strong>处理中(pending)</strong> 的 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise</a>。 只要传入的迭代对象中的任何一个 <code>promise</code> 变成成功(resolve)状态,或者其中的所有的 <code>promises</code> 都失败,那么返回的 <code>promise</code> 就会 <strong>异步地</strong>(当调用栈为空时)<strong> </strong>变成成功/失败(resolved/reject)状态。</li> +</ul> + +<h2 id="说明">说明</h2> + +<p>这个方法用于返回第一个成功的 <code>promise</code> 。只要有一个 <code>promise</code> 成功此方法就会终止,它不会等待其他的 <code>promise</code> 全部完成。</p> + +<p>不像 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/all">Promise.all()</a> 会返回一组完成值那样(resolved values),我们只能得到一个成功值(假设至少有一个 <code>promise</code> 完成)。当我们只需要一个 <code>promise</code> 成功,而不关心是哪一个成功时此方法很有用的。</p> + +<p>同时, 也不像 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/race">Promise.race()</a> 总是返回第一个结果值(resolved/reject)那样,这个方法返回的是第一个<em> 成功的</em> 值。这个方法将会忽略掉所有被拒绝的 <code>promise</code>,直到第一个 <code>promise</code> 成功。</p> + +<h3 id="成功(Fulfillment):">成功(Fulfillment):</h3> + +<p>当任何一个被传入的 <code>promise</code> 成功的时候, 无论其他的 <code>promises</code> 成功还是失败,此函数会将那个成功的 <code>promise</code> 作为返回值 。</p> + +<ul> + <li>如果传入的参数是一个空的可迭代对象, 这个方法将会同步返回一个已经完成的 <code>promise</code>。</li> + <li>如果传入的任何一个 <code>promise</code> 已成功, 或者传入的参数不包括任何 <code>promise</code>, 那么 <code>Promise.any</code> 返回一个异步成功的 <code>promise</code>。</li> +</ul> + +<h3 id="失败拒绝(Rejection):">失败/拒绝(Rejection):</h3> + +<p>如果所有传入的 <code>promises</code> 都失败, <code>Promise.any</code> 将返回异步失败,和一个 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError">AggregateError</a> 对象,它继承自 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Error">Error</a>,有一个 <code>error</code> 属性,属性值是由所有失败值填充的数组。</p> + +<h2 id="示例">示例</h2> + +<h3 id="First_to_fulfil">First to fulfil</h3> + +<p>即使第一个返回的 promise 是失败的,<code>Promise.any()</code> 依然使用第一个成功状态的 promise 来返回。这与使用首个(无论 rejected 还是 fullfiled)promise 来返回的 {{jsxref("Promise.race()")}} 相反。</p> + +<pre class="brush: js notranslate">const pErr = new Promise((resolve, reject) => { + reject("总是失败"); +}); + +const pSlow = new Promise((resolve, reject) => { + setTimeout(resolve, 500, "最终完成"); +}); + +const pFast = new Promise((resolve, reject) => { + setTimeout(resolve, 100, "很快完成"); +}); + +Promise.any([pErr, pSlow, pFast]).then((value) => { + console.log(value); + // pFast fulfils first +}) +// 期望输出: "很快完成" +</pre> + +<h3 id="Rejections_with_AggregateError">Rejections with AggregateError</h3> + +<p>如果没有 fulfilled (成功的) promise,<code>Promise.any()</code> 返回 {{jsxref("AggregateError")}} 错误。</p> + +<pre class="brush: js notranslate">const pErr = new Promise((resolve, reject) => { + reject('总是失败'); +}); + +Promise.any([pErr]).catch((err) => { + console.log(err); +}) +// 期望输出: "AggregateError: No Promise in Promise.any was resolved" +</pre> + +<h3 id="显示第一张已加载的图片">显示第一张已加载的图片</h3> + +<p>在这个例子,我们有一个获取图片并返回 blob 的函数,我们使用 <code>Promise.any()</code> 来获取一些图片并显示第一张有效的图片(即最先 resolved 的那个 promise)。</p> + +<pre class="brush: js notranslate">function fetchAndDecode(url) { + return fetch(url).then(response => { + if(!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } else { + return response.blob(); + } + }) +} + +let coffee = fetchAndDecode('coffee.jpg'); +let tea = fetchAndDecode('tea.jpg'); + +Promise.any([coffee, tea]).then(value => { + let objectURL = URL.createObjectURL(value); + let image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); +}) +.catch(e => { + console.log(e.message); +});</pre> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">规范</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{SpecName('Promise.any')}}</td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + + + +<p>{{Compat("javascript.builtins.Promise.any")}}</p> + +<h2 id="参见">参见</h2> + +<ul> + <li>{{JSxRef("Promise")}}</li> + <li>{{JSxRef("Promise.all()")}}</li> + <li>{{JSxRef("Promise.race()")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/global_objects/promise/catch/index.html b/files/zh-cn/web/javascript/reference/global_objects/promise/catch/index.html new file mode 100644 index 0000000000..3bd0a41fd4 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/promise/catch/index.html @@ -0,0 +1,156 @@ +--- +title: Promise.prototype.catch() +slug: Web/JavaScript/Reference/Global_Objects/Promise/catch +tags: + - Promise + - Promise.prototype.catch() +translation_of: Web/JavaScript/Reference/Global_Objects/Promise/catch +--- +<div>{{JSRef}}</div> + +<p><strong>catch()</strong> 方法返回一个<a href="/zh-CN/docs/Web/API/Promise">Promise</a>,并且处理拒绝的情况。它的行为与调用{{jsxref("Promise.then", "Promise.prototype.then(undefined, onRejected)")}} 相同。 (事实上, calling <code>obj.catch(onRejected)</code> 内部calls <code>obj.then(undefined, onRejected)</code>).</p> + +<h2 id="Syntax" name="Syntax" style="line-height: 30px;">语法</h2> + +<pre class="syntaxbox" style="font-size: 14px;"><var>p.catch(onRejected)</var>; + +p.catch(function(reason) { + // 拒绝 +}); +</pre> + +<h3 id="参数" style="line-height: 24px;">参数</h3> + +<dl> + <dt><strong>onRejected</strong></dt> + <dd>当Promise 被rejected时,被调用的一个{{jsxref("Function")}}。 该函数拥有一个参数:</dd> + <dd><code>reason</code> rejection 的原因。</dd> + <dd> + <p> 如果 <code>onRejected</code> 抛出一个错误或返回一个本身失败的 Promise , 通过 <code>catch()</code> 返回的Promise 被rejected;否则,它将显示为成功(resolved)。 </p> + + <h3 id="返回值">返回值</h3> + + <p>一个{{jsxref("Promise")}}.</p> + </dd> +</dl> + +<h2 id="Description" name="Description" style="line-height: 30px;">描述</h2> + +<p><code>catch </code>方法可以用于您的promise组合中的错误处理。</p> + +<p>Internally calls <code>Promise.prototype.then</code> on the object upon which is called, passing the parameters <code>undefined</code> and the <code>onRejected</code> handler received; then returns the value of that call (which is a {{jsxref("Promise")}}).</p> + +<h2 id="示例" style="line-height: 30px;">示例</h2> + +<h3 id="使用链式语句的_catch方法" style="line-height: 24px;">使用链式语句的 <code>catch</code>方法</h3> + +<pre class="brush: js"><code>var p1 = new Promise(function(resolve, reject) { + resolve('Success'); +});</code> + +p1.then(function(value) { + console.log(value); // "Success!" + throw 'oh, no!'; +}).catch(function(e) { + console.log(e); // "oh, no!" +}).then(function(){ + console.log('after a catch the chain is restored'); +}, function () { + console.log('Not fired due to the catch'); +}); + +// 以下行为与上述相同 +p1.then(function(value) { + console.log(value); // "Success!" + return Promise.reject('oh, no!'); +}).catch(function(e) { + console.log(e); // "oh, no!" +}).then(function(){ + console.log('after a catch the chain is restored'); +}, function () { + console.log('Not fired due to the catch'); +});</pre> + +<h3 id="捕获抛出的错误" style="line-height: 30px;">捕获抛出的错误</h3> + +<pre class="brush: js"><code>// 抛出一个错误,大多数时候将调用catch方法 +var p1 = new Promise(function(resolve, reject) { + throw 'Uh-oh!'; +}); + +p1.catch(function(e) { + console.log(e); // "Uh-oh!" +}); + +// 在异步函数中抛出的错误不会被catch捕获到 +var p2 = new Promise(function(resolve, reject) { + setTimeout(function() { + throw 'Uncaught Exception!'; + }, 1000); +}); + +p2.catch(function(e) { + console.log(e); // 不会执行 +}); + +// 在resolve()后面抛出的错误会被忽略 +var p3 = new Promise(function(resolve, reject) { + resolve(); + throw 'Silenced Exception!'; +}); + +p3.catch(function(e) { + console.log(e); // 不会执行 +});</code></pre> + +<h3 id="如果已决议" style="line-height: 30px;">如果已决议</h3> + +<pre><code>//创建一个新的 Promise ,且已决议 +var p1 = Promise.resolve("calling next"); + +var p2 = p1.catch(function (reason) { + //这个方法永远不会调用 + console.log("catch p1!"); + console.log(reason); +}); + +p2.then(function (value) { + console.log("next promise's onFulfilled"); /* next promise's onFulfilled */ + console.log(value); /* calling next */ +}, function (reason) { + console.log("next promise's onRejected"); + console.log(reason); +});</code></pre> + +<h2 id="规范" style="line-height: 30px;">规范</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">规范</th> + <th scope="col">状态</th> + <th scope="col">备注</th> + </tr> + <tr> + <td><a href="https://github.com/domenic/promises-unwrapping">domenic/promises-unwrapping</a></td> + <td>{{Spec2('ES6')}}</td> + <td>Initial definition in an ECMA standard.</td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-promise.prototype.catch', 'Promise.prototype.catch')}}</td> + <td>{{Spec2('ES6')}}</td> + <td> </td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性" style="line-height: 30px;">浏览器兼容性</h2> + +<p>{{Compat("javascript/promise","Promise.prototype.catch")}}</p> + +<h2 id="相关链接" style="line-height: 30px;">相关链接</h2> + +<ul> + <li>{{jsxref("Promise")}}</li> + <li>{{jsxref("Promise.prototype.then()")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/global_objects/promise/finally/index.html b/files/zh-cn/web/javascript/reference/global_objects/promise/finally/index.html new file mode 100644 index 0000000000..6f0711e765 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/promise/finally/index.html @@ -0,0 +1,101 @@ +--- +title: Promise.prototype.finally() +slug: Web/JavaScript/Reference/Global_Objects/Promise/finally +tags: + - JavaScript + - Promises + - Reference + - finally +translation_of: Web/JavaScript/Reference/Global_Objects/Promise/finally +--- +<div>{{JSRef}}</div> + +<div></div> + +<div><code><strong>finally()</strong></code> 方法返回一个{{jsxref("Promise")}}。在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。这为在<code>Promise</code>是否成功完成后都需要执行的代码提供了一种方式。</div> + +<div>这避免了同样的语句需要在{{jsxref("Promise.then", "then()")}}和{{jsxref("Promise.catch", "catch()")}}中各写一次的情况。</div> + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox"><var>p.finally(onFinally)</var>; + +p.finally(function() { + // 返回状态为(resolved 或 rejected) +});</pre> + +<h3 id="参数">参数</h3> + +<dl> + <dt><code>onFinally</code></dt> + <dd><code>Promise</code> 结束后调用的{{jsxref("Function")}}。</dd> +</dl> + +<h3 id="返回值">返回值</h3> + +<p>返回一个设置了 <code>finally</code> 回调函数的{{jsxref("Promise")}}对象。 </p> + +<h2 id="描述">描述</h2> + +<p>如果你想在 promise 执行完毕后无论其结果怎样都做一些处理或清理时,<code>finally()</code> 方法可能是有用的。</p> + +<p><code>finally()</code> 虽然与 <code>.then(onFinally, onFinally)</code> 类似,它们不同的是:</p> + +<ul> + <li>调用内联函数时,不需要多次声明该函数或为该函数创建一个变量保存它。</li> + <li>由于无法知道<code>promise</code>的最终状态,所以<code>finally</code>的回调函数中不接收任何参数,它仅用于无论最终结果如何都要执行的情况。</li> + <li>与<code>Promise.resolve(2).then(() => {}, () => {})</code> (resolved的结果为<code>undefined</code>)不同,<code>Promise.resolve(2).finally(() => {})</code> resolved的结果为 <code>2</code>。</li> + <li>同样,<code>Promise.reject(3).then(() => {}, () => {})</code> (resolved 的结果为<code>undefined</code>), <code>Promise.reject(3).finally(() => {})</code> rejected 的结果为 <code>3</code>。</li> +</ul> + +<div class="note"> +<p><strong>注意:</strong> 在<code>finally</code>回调中 <code>throw</code>(或返回被拒绝的promise)将以 <code>throw()</code> 指定的原因拒绝新的promise.</p> +</div> + +<h2 id="示例">示例</h2> + +<pre class="brush: js">let isLoading = true; + +fetch(myRequest).then(function(response) { + var contentType = response.headers.get("content-type"); + if(contentType && contentType.includes("application/json")) { + return response.json(); + } + throw new TypeError("Oops, we haven't got JSON!"); + }) + .then(function(json) { /* process your JSON further */ }) + .catch(function(error) { console.log(error); }) + .finally(function() { isLoading = false; }); + +</pre> + +<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('ESDraft', '#sec-promise.prototype.finally', 'Promise.prototype.finally')}}</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.finally")}}</p> + +<h2 id="参见">参见</h2> + +<ul> + <li>{{jsxref("Promise")}}</li> + <li>{{jsxref("Promise.prototype.then()")}}</li> + <li>{{jsxref("Promise.prototype.catch()")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/global_objects/promise/index.html b/files/zh-cn/web/javascript/reference/global_objects/promise/index.html new file mode 100644 index 0000000000..5378fe3aeb --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/promise/index.html @@ -0,0 +1,311 @@ +--- +title: Promise +slug: Web/JavaScript/Reference/Global_Objects/Promise +tags: + - ECMAScript 2015 + - ES6 + - JavaScript + - Promise + - Promise A+ + - Reference +translation_of: Web/JavaScript/Reference/Global_Objects/Promise +--- +<p>{{JSRef}}</p> + +<p id="概述"><strong>Promise </strong>对象用于表示一个异步操作的最终完成 (或失败)及其结果值。</p> + +<p>若想了解 promises 的工作方式以及如何使用它们,我们建议您先阅读<a href="/zh-CN/docs/Web/JavaScript/Guide/Using_promises">使用 promises</a></p> + +<h2 id="描述">描述</h2> + +<p>一个 <code>Promise</code> 对象代表一个在这个 promise 被创建出来时不一定已知的值。它让您能够把异步操作最终的成功返回值或者失败原因和相应的处理程序关联起来。 这样使得异步方法可以像同步方法那样返回值:异步方法并不会立即返回最终的值,而是会返回一个 <em>promise</em>,以便在未来某个时候把值交给使用者。</p> + +<p>一个 <code>Promise</code> 必然处于以下几种状态之一:</p> + +<ul> + <li><em>待定(pending)</em>: 初始状态,既没有被兑现,也没有被拒绝。</li> + <li><em>已兑现(fulfilled)</em>: 意味着操作成功完成。</li> + <li><em>已拒绝(rejected)</em>: 意味着操作失败。</li> +</ul> + +<p>待定状态的 Promise 对象要么会通过一个值<em>被兑现(fulfilled)</em>,要么会通过一个原因(错误)<em>被拒绝(rejected)</em>。当这些情况之一发生时,我们用 promise 的 then 方法排列起来的相关处理程序就会被调用。如果 promise 在一个相应的处理程序被绑定时就已经被兑现或被拒绝了,那么这个处理程序就会被调用,因此<span style="line-height: 1.5;">在完成异步操作和绑定处理方法之间不会存在竞争状态。</span></p> + +<p>因为 <span style="font-family: consolas,monaco,andale mono,monospace;"><code>{{jsxref("Promise.then", "Promise.prototype.then")}}</code> </span>和 <code style="font-style: normal;">{{jsxref("Promise.catch", "Promise.prototype.catch")}}</code> 方法返回的是 promise, 所以它们可以被链式调用。</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/8633/promises.png" style="height: 297px; width: 801px;"></p> + +<div class="note"> +<p><strong>不要和惰性求值混淆:</strong> 有一些语言中有惰性求值和延时计算的特性,它们也被称为“promises”,例如 Scheme。JavaScript 中的 promise 代表的是已经正在发生的进程, 而且可以通过回调函数实现链式调用。 如果您想对一个表达式进行惰性求值,就考虑一下使用无参数的"<a href="/zh-CN/docs/Web/JavaScript/Reference/Functions/Arrow_functions">箭头函数</a>": <code>f = () =></code><em><code>表达式</code> </em>来创建惰性求值的表达式<em>,</em>使用 <code>f()</code><strong> </strong>求值。</p> +</div> + +<div class="note"> +<p><strong>注意:</strong> 如果一个 promise 已经被兑现(fulfilled)或被拒绝(rejected),那么我们也可以说它处于<em>已敲定(settled)</em>状态。您还会听到一个经常跟 promise 一起使用的术语:<em>已决议(resolved)</em>,它表示 promise 已经处于已敲定(settled)状态,或者为了匹配另一个 promise 的状态被"锁定"了。Domenic Denicola 的 <a href="https://github.com/domenic/promises-unwrapping/blob/master/docs/states-and-fates.md">States and fates</a> 中有更多关于 promise 术语的细节可以供您参考。</p> +</div> + +<h3 id="Promise的链式调用">Promise的链式调用</h3> + +<p>我们可以用 <code>promise.then()</code>,<code>promise.catch()</code> 和 <code>promise.finally()</code> 这些方法将进一步的操作与一个变为已敲定状态的 promise 关联起来。这些方法还会返回一个新生成的 promise 对象,这个对象可以被非强制性的用来做链式调用,就像这样:</p> + +<pre class="notranslate">const myPromise = + (new Promise(myExecutorFunc)) + .then(handleFulfilledA,handleRejectedA) + .then(handleFulfilledB,handleRejectedB) + .then(handleFulfilledC,handleRejectedC); + +// 或者,这样可能会更好... + +const myPromise = + (new Promise(myExecutorFunc)) + .then(handleFulfilledA) + .then(handleFulfilledB) + .then(handleFulfilledC) + .catch(handleRejectedAny);</pre> + +<p>过早地处理被拒绝的 promise 会对之后 promise 的链式调用造成影响。不过有时候我们因为需要马上处理一个错误也只能这样做。(有关应对影响的技巧,请参见下面示例中的 <code>throw -999</code> )另一方面,在没有迫切需要的情况下,可以在最后一个.catch() 语句时再进行错误处理,这种做法更加简单。</p> + +<p>这两个函数的签名很简单,它们只接受一个任意类型的参数。这些函数由您(编程者)编写。这些函数的终止状态决定着链式调用中下一个promise的"已敲定 (settled)"状态是什么。任何不是 <code>throw</code> 的终止都会创建一个"已决议(resolved)"状态,而以 <code>throw</code> 终止则会创建一个"已拒绝"状态。</p> + +<pre class="notranslate">handleFulfilled(value) { /*...*/; return nextValue; } +handleRejection(reason) { /*...*/; throw nextReason; } +handleRejection(reason) { /*...*/; return nextValue; }</pre> + +<p>被返回的 <code>nextValue</code> 可能是另一个promise对象,这种情况下这个promise会被动态地插入链式调用。 </p> + +<p>当 <code>.then()</code> 中缺少能够返回 promise 对象的函数时,链式调用就直接继续进行下一环操作。因此,链式调用可以在最后一个 <code>.catch()</code> 之前把所有的 <code>handleRejection</code> 都省略掉。类似地, <code>.catch()</code> 其实只是没有给 <code>handleFulfilled</code> 预留参数位置的 <code>.then()</code> 而已。</p> + +<p>链式调用中的 promise 们就像俄罗斯套娃一样,是嵌套起来的,但又像是一个栈,每个都必须从顶端被弹出。链式调用中的第一个 promise 是嵌套最深的一个,也将是第一个被弹出的。</p> + +<pre class="notranslate">(promise D, (promise C, (promise B, (promise A) ) ) )</pre> + +<p>当存在一个 <code>nextValue</code> 是 promise 时,就会出现一种动态的替换效果。<code>return</code> 会导致一个 promise 被弹出,但这个 <code>nextValue</code> promise 则会被推入被弹出 promise 原来的位置。对于上面所示的嵌套场景,假设与 "promise B" 相关的 <code>.then()</code> 返回了一个值为 "promise X" 的 <code>nextValue</code> 。那么嵌套的结果看起来就会是这样:</p> + +<pre class="notranslate">(promise D, (promise C, (promise X) ) )</pre> + +<p>一个 promise 可能会参与不止一次的嵌套。对于下面的代码,<code>promiseA</code> 向"已敲定"("settled")状态的过渡会导致两个实例的 <code>.then</code> 都被调用。</p> + +<pre class="notranslate">const promiseA = new Promise(myExecutorFunc); +const promiseB = promiseA.then(handleFulfilled1, handleRejected1); +const promiseC = promiseA.then(handleFulfilled2, handleRejected2); </pre> + +<p>一个已经处于"已敲定"("settled")状态的 promise 也可以接收操作。在那种情况下,(如果没有问题的话,)这个操作会被作为第一个异步操作被执行。注意,所有的 promise 都一定是异步的。因此,一个已经处于"已敲定"("settled")状态的 promise 中的操作只有 promise 链式调用的栈被清空了和一个事件循环过去了之后才会被执行。这种效果跟 <code>setTimeout(action, 10)</code> 特别相似。</p> + +<pre class="notranslate">const promiseA = new Promise( (resolutionFunc,rejectionFunc) => { + resolutionFunc(777); +}); +// 这时,"promiseA" 已经被敲定了。 +promiseA.then( (val) => console.log("asynchronous logging has val:",val) ); +console.log("immediate logging"); + +// produces output in this order: +// immediate logging +// asynchronous logging has val: 777 +</pre> + +<h2 id="构造函数">构造函数</h2> + +<dl> + <dt>{{jsxref("Promise/Promise", "Promise()")}}</dt> + <dd>创建一个新的 <code>Promise</code> 对象。该构造函数主要用于包装还没有添加 promise 支持的函数。</dd> +</dl> + +<h2 id="静态方法">静态方法</h2> + +<dl> + <dt>{{jsxref("Promise.all", "Promise.all(iterable)")}}</dt> + <dd>这个方法返回一个新的promise对象,该promise对象在iterable参数对象里所有的promise对象都成功的时候才会触发成功,一旦有任何一个iterable里面的promise对象失败则立即触发该promise对象的失败。这个新的promise对象在触发成功状态以后,会把一个包含iterable里所有promise返回值的数组作为成功回调的返回值,顺序跟iterable的顺序保持一致;如果这个新的promise对象触发了失败状态,它会把iterable里第一个触发失败的promise对象的错误信息作为它的失败错误信息。Promise.all方法常被用于处理多个promise对象的状态集合。(可以参考jQuery.when方法---译者注)</dd> +</dl> + +<dl> + <dt>{{jsxref("Promise.allSettled", "Promise.allSettled(iterable)")}}</dt> + <dd>等到所有promises都已敲定(settled)(每个promise都已兑现(fulfilled)或已拒绝(rejected))。<br> + 返回一个promise,该promise在所有promise完成后完成。并带有一个对象数组,每个对象对应每个promise的结果。</dd> +</dl> + +<dl> + <dt>{{jsxref("Promise.any", "Promise.any(iterable)")}}</dt> + <dd>接收一个Promise对象的集合,当其中的一个 promise 成功,就返回那个成功的promise的值。</dd> +</dl> + +<dl> + <dt>{{jsxref("Promise.race", "Promise.race(iterable)")}}</dt> + <dd>当iterable参数里的任意一个子promise被成功或失败后,父promise马上也会用子promise的成功返回值或失败详情作为参数调用父promise绑定的相应句柄,并返回该promise对象。</dd> +</dl> + +<dl> + <dt>{{jsxref("Promise.reject", "Promise.reject(reason)")}}</dt> + <dd>返回一个状态为失败的Promise对象,并将给定的失败信息传递给对应的处理方法</dd> +</dl> + +<dl> + <dt>{{jsxref("Promise.resolve", "Promise.resolve(value)")}}</dt> + <dd>返回一个状态由给定value决定的Promise对象。如果该值是thenable(即,带有then方法的对象),返回的Promise对象的最终状态由then方法执行决定;否则的话(该value为空,基本类型或者不带then方法的对象),返回的Promise对象状态为fulfilled,并且将该value传递给对应的then方法。通常而言,如果您不知道一个值是否是Promise对象,使用Promise.resolve(value) 来返回一个Promise对象,这样就能将该value以Promise对象形式使用。</dd> +</dl> + +<h2 id="Promise_原型">Promise 原型</h2> + +<h3 id="属性">属性</h3> + +<p>{{page('zh-CN/Web/JavaScript/Reference/Global_Objects/Promise/prototype','属性')}}</p> + +<h3 id="方法">方法</h3> + +<p>{{page('zh-CN/Web/JavaScript/Reference/Global_Objects/Promise/prototype','方法')}}</p> + +<h2 id="创建Promise">创建Promise</h2> + +<p><code>Promise</code> 对象是由关键字 <code>new</code> 及其构造函数来创建的。该构造函数会把一个叫做“处理器函数”(executor function)的函数作为它的参数。这个“处理器函数”接受两个函数——<code>resolve</code> 和 <code>reject</code> ——作为其参数。当异步任务顺利完成且返回结果值时,会调用 <code>resolve</code> 函数;而当异步任务失败且返回失败原因(通常是一个错误对象)时,会调用<code>reject</code> 函数。</p> + +<pre class="brush: js notranslate">const myFirstPromise = new Promise((resolve, reject) => { + // ?做一些异步操作,最终会调用下面两者之一: + // + // resolve(someValue); // fulfilled + // ?或 + // reject("failure reason"); // rejected +});</pre> + +<p>想要某个函数拥有promise功能,只需让其返回一个promise即可。</p> + +<pre class="brush: js notranslate">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 notranslate">let myFirstPromise = new Promise(function(resolve, reject){ + //当异步代码执行成功时,我们才会调用resolve(...), 当异步代码失败时就会调用reject(...) + //在本例中,我们使用setTimeout(...)来模拟异步代码,实际编码时可能是XHR请求或是HTML5的一些API方法. + setTimeout(function(){ + resolve("成功!"); //代码正常执行! + }, 250); +}); + +myFirstPromise.then(function(successMessage){ + //successMessage的值是上面调用resolve(...)方法传入的值. + //successMessage参数不一定非要是字符串类型,这里只是举个例子 + console.log("Yay! " + successMessage); +}); +</pre> + +<h3 id="高级示例">高级示例</h3> + +<pre class="brush: html hidden notranslate"><button id="btn">Make a promise!</button> +<div id="log"></div> +</pre> + +<p>本例展示了 <code>Promise</code> 的一些机制。 <code>testPromise()</code> 方法在每次点击 {{HTMLElement("button")}} 按钮时被调用,该方法会创建一个promise 对象,使用 {{domxref("window.setTimeout()")}} 让Promise等待 1-3 秒不等的时间来填充数据(通过Math.random()方法)。</p> + +<p>Promise 的值的填充过程都被日志记录(logged)下来,这些日志信息展示了方法中的同步代码和异步代码是如何通过Promise完成解耦的。</p> + +<pre class="brush: js notranslate">'use strict'; +var promiseCount = 0; + +function testPromise() { + let thisPromiseCount = ++promiseCount; + + let log = document.getElementById('log'); + log.insertAdjacentHTML('beforeend', thisPromiseCount + + ') 开始 (<small>同步代码开始</small>)<br/>'); + + // 新构建一个 Promise 实例:使用Promise实现每过一段时间给计数器加一的过程,每段时间间隔为1~3秒不等 + let p1 = new Promise( + // resolver 函数在 Promise 成功或失败时都可能被调用 + (resolve, reject) => { + log.insertAdjacentHTML('beforeend', thisPromiseCount + + ') Promise 开始 (<small>异步代码开始</small>)<br/>'); + // 创建一个异步调用 + window.setTimeout( + function() { + // 填充 Promise + resolve(thisPromiseCount); + }, Math.random() * 2000 + 1000); + } + ); + + // Promise 不论成功或失败都会调用 then + // catch() 只有当 promise 失败时才会调用 + p1.then( + // 记录填充值 + function(val) { + log.insertAdjacentHTML('beforeend', val + + ') Promise 已填充完毕 (<small>异步代码结束</small>)<br/>'); + }) + .catch( + // 记录失败原因 + (reason) => { + console.log('处理失败的 promise ('+reason+')'); + }); + + log.insertAdjacentHTML('beforeend', thisPromiseCount + + ') Promise made (<small>同步代码结束</small>)<br/>'); +}</pre> + +<pre class="brush:js hidden notranslate">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>点击下面的按钮可以看到示例代码运行的效果,前提是您的浏览器支持 <code>Promise</code>。快速点击按钮多次您会观察到Promises填充值的过程。</p> + +<p>{{EmbedLiveSample("高级一点的例子", "500", "200")}}</p> + +<h2 id="使用_XHR_加载图像">使用 XHR 加载图像</h2> + +<p><font face="Open Sans, sans-serif">另一个用了 </font>Promise <font face="Open Sans, sans-serif">和</font><a href="/en-US/docs/Web/API/XMLHttpRequest"> XMLHttpRequest</a> 加载一个图像的例子可在MDN GitHub<a href="https://github.com/mdn/js-examples/tree/master/promises-test"> promise-test</a> 中找到。 您也可以<a href="https://mdn.github.io/js-examples/promises-test/">看这个实例</a>。每一步都有注释可以让您详细的了解Promise和XHR架构。</p> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">规范</th> + <th scope="col">状态</th> + <th scope="col">备注</th> + </tr> + <tr> + <td>{{SpecName('ES2015', '#sec-promise-objects', 'Promise')}}</td> + <td>{{Spec2('ES2015')}}</td> + <td>ECMA标准中的首次定义</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="https://developer.mozilla.org/en-US/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 Patter 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="https://github.com/anonyco/SPromiseMeSpeedJS/blob/master/README.md">Speed-polyfill to polyfill both promise availability and promise performance.</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> diff --git a/files/zh-cn/web/javascript/reference/global_objects/promise/promise/index.html b/files/zh-cn/web/javascript/reference/global_objects/promise/promise/index.html new file mode 100644 index 0000000000..c871b52513 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/promise/promise/index.html @@ -0,0 +1,73 @@ +--- +title: Promise() 构造器 +slug: Web/JavaScript/Reference/Global_Objects/Promise/Promise +translation_of: Web/JavaScript/Reference/Global_Objects/Promise/Promise +--- +<div>{{JSRef}}</div> + +<p><strong><code>Promise</code></strong> 构造器主要用于包装不支持promise(返回值不是<code>Promise</code>)的函数。</p> + +<div>{{EmbedInteractiveExample("pages/js/promise-constructor.html")}}</div> + +<p class="hidden">交互式的demo的源码在GitHub仓库,如果你乐于为交互式的demo做贡献,请克隆<a href="https://github.com/mdn/interactive-examples">https://github.com/mdn/interactive-examples</a>并提交pull request .</p> + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox">new Promise(<var>executor</var>)</pre> + +<h3 id="参数">参数</h3> + +<dl> + <dt><code>executor</code></dt> + <dd>这是一个双参函数,参数为<code>resolve<font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">和</span></font>reject</code>。<code>Promise</code>的实现会立即执行<code>executor</code>,并传入<code>resolve<font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">和</span></font>reject</code>函数(<code>Promise</code>构造器将会在返回新对象之前<code>executor</code>)。当<code>resolve</code>和<code>reject</code>函数被调用时,它们分别对promise执行<code>resolve</code>和<code>reject</code>。<code>executor</code>通常会触发一些异步运算,一旦运算成功完成,则<code>resolve</code>掉这个promise,如果出错则<code>reject</code>掉。如果<code>executor</code>函数执行时抛出异常,promise状态会变为<code>rejected</code>。<code>executor</code>的返回值也会被忽略。</dd> +</dl> + +<h2 id="例子">例子</h2> + +<p>我们通过<code>new</code>关键字和<code>Promise</code>构造器创建它的对象。这个构造器接受一个名为"executor function"的函数。这个函数应当接受两个函数参数。当异步任务成功时,第一个函数(<code>resolve</code>)将被调用,并返回一个值代表成功。当其失败时,第二个函数(<code>reject</code>)将被调用,并返回失败原因(失败原因通常是一个error对象)。</p> + +<pre class="brush: js;">const myFirstPromise = new Promise((resolve, reject) => { + // do something asynchronous which eventually calls either: + // + // resolve(someValue) // fulfilled + // or + // reject("failure reason") // rejected +}); +</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> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">Specification</th> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-promise-constructor', 'Promise constructor')}}</td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + +<div 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>.</div> + +<p>{{Compat("javascript.builtins.Promise.Promise")}}</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="/en-US/docs/Web/JavaScript/Guide/Using_promises">Using Promises</a></li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/global_objects/promise/prototype/index.html b/files/zh-cn/web/javascript/reference/global_objects/promise/prototype/index.html new file mode 100644 index 0000000000..3b26852c87 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/promise/prototype/index.html @@ -0,0 +1,115 @@ +--- +title: Promise.prototype +slug: Web/JavaScript/Reference/Global_Objects/Promise/prototype +translation_of: Web/JavaScript/Reference/Global_Objects/Promise +--- +<div>{{JSRef("Global_Objects", "Promise")}}</div> + +<h2 id="Summary" name="Summary">总结</h2> + +<p><code><strong>Promise</strong></code><strong><code>.prototype</code></strong> 属性表示 {{jsxref("Promise")}} 构造器的原型.</p> + +<div>{{js_property_attributes(0,0,0)}}</div> + +<h2 id="Description" name="Description">描述</h2> + +<p>{{jsxref("Promise")}} 实例继承自 {{jsxref("Promise.prototype")}}. 你可以在构造器的原型对象添加属性或方法到所有 <code>Promise</code> 实例上.</p> + +<h2 id="属性">属性</h2> + +<dl> + <dt><code>Promise.prototype.constructor</code></dt> + <dd>返回被创建的实例函数. 默认为 {{jsxref("Promise")}} 函数.</dd> +</dl> + +<h2 id="方法">方法</h2> + +<dl> + <dt>{{jsxref("Promise.catch", "Promise.prototype.catch(onRejected)")}}</dt> + <dd>添加一个拒绝(rejection) 回调到当前 promise, 返回一个新的promise。当这个回调函数被调用,新 promise 将以它的返回值来resolve,否则如果当前promise 进入fulfilled状态,则以当前promise的完成结果作为新promise的完成结果.</dd> + <dt>{{jsxref("Promise.then", "Promise.prototype.then(onFulfilled, onRejected)")}}</dt> + <dd>添加解决(fulfillment)和拒绝(rejection)回调到当前 promise, 返回一个新的 promise, 将以回调的返回值来resolve.</dd> + <dt>{{jsxref("Promise.finally", "Promise.prototype.finally(onFinally)")}}</dt> + <dd>添加一个事件处理回调于当前promise对象,并且在原promise对象解析完毕后,返回一个新的promise对象。回调会在当前promise运行完毕后被调用,无论当前promise的状态是完成(fulfilled)还是失败(rejected)</dd> +</dl> + +<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('ES6', '#sec-promise.prototype', 'Promise.prototype')}}</td> + <td>{{Spec2('ES6')}}</td> + <td>Initial definition.</td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容">浏览器兼容</h2> + +<p>{{CompatibilityTable}}</p> + +<div id="compat-desktop"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Chrome</th> + <th>Firefox (Gecko)</th> + <th>Internet Explorer</th> + <th>Opera</th> + <th>Safari</th> + </tr> + <tr> + <td>Basic support</td> + <td>32</td> + <td>{{CompatGeckoDesktop(24.0)}} as <code>Future</code><br> + {{CompatGeckoDesktop(25.0)}} as <code>Promise</code> behind a flag[1]<br> + {{CompatGeckoDesktop(29.0)}} by default</td> + <td>{{CompatNo}}</td> + <td>19</td> + <td>7.1</td> + </tr> + </tbody> +</table> +</div> + +<div id="compat-mobile"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Android</th> + <th>Firefox Mobile (Gecko)</th> + <th>IE Mobile</th> + <th>Opera Mobile</th> + <th>Safari Mobile</th> + <th>Chrome for Android</th> + </tr> + <tr> + <td>Basic support</td> + <td>{{CompatNo}}</td> + <td>{{CompatGeckoMobile(24.0)}} as <code>Future</code><br> + {{CompatGeckoMobile(25.0)}} as <code>Promise</code> behind a flag[1]<br> + {{CompatGeckoMobile(29.0)}} by default</td> + <td>{{CompatNo}}</td> + <td>{{CompatNo}}</td> + <td>iOS 8</td> + <td>32</td> + </tr> + </tbody> +</table> +</div> + +<p>[1] Gecko 24 has an experimental implementation of <code>Promise</code>, under the initial name of <code>Future</code>. It got renamed to its final name in Gecko 25, but disabled by default behind the flag <code>dom.promise.enabled</code>. <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=918806">Bug 918806</a> enabled Promises by default in Gecko 29.</p> + +<h2 id="另见">另见</h2> + +<ul> + <li>{{jsxref("Promise")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/global_objects/promise/race/index.html b/files/zh-cn/web/javascript/reference/global_objects/promise/race/index.html new file mode 100644 index 0000000000..1220002fe1 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/promise/race/index.html @@ -0,0 +1,138 @@ +--- +title: Promise.race() +slug: Web/JavaScript/Reference/Global_Objects/Promise/race +tags: + - Promise +translation_of: Web/JavaScript/Reference/Global_Objects/Promise/race +--- +<div>{{JSRef}}</div> + +<p><strong><code>Promise.race(iterable)</code> </strong>方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。</p> + +<div>{{EmbedInteractiveExample("pages/js/promise-race.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="Syntax" name="Syntax">语法</h2> + +<pre class="syntaxbox notranslate"><var>Promise.race(iterable)</var>;</pre> + +<h3 id="参数"><strong>参数</strong></h3> + +<dl> + <dt>iterable</dt> + <dd>可迭代对象,类似{{jsxref("Array")}}。详见 <a href="/en-US/docs/Web/JavaScript/Guide/iterable">iterable</a>。</dd> +</dl> + +<h3 id="返回值">返回值</h3> + +<p>一个<strong>待定的</strong> {{jsxref("Promise")}} 只要给定的迭代中的一个promise解决或拒绝,就采用第一个promise的值作为它的值,从而<strong>异步</strong>地解析或拒绝(一旦堆栈为空)。</p> + +<h2 id="Description" name="Description">描述</h2> + +<p><code>race</code> 函数返回一个 <code>Promise</code>,它将与第一个传递的 promise 相同的完成方式被完成。它可以是完成( resolves),也可以是失败(rejects),这要取决于第一个完成的方式是两个中的哪个。</p> + +<p>如果传的迭代是空的,则返回的 promise 将永远等待。</p> + +<p>如果迭代包含一个或多个非承诺值和/或已解决/拒绝的承诺,则<code> Promise.race</code> 将解析为迭代中找到的第一个值。</p> + +<h2 id="示例">示例</h2> + +<h3 id="Promise.race的异步性">Promise.race的异步性</h3> + +<pre class="brush: js notranslate">// we are passing as argument an array of promises that are already resolved, +// to trigger Promise.race as soon as possible +var resolvedPromisesArray = [Promise.resolve(33), Promise.resolve(44)]; + +var p = Promise.race(resolvedPromisesArray); +// immediately logging the value of p +console.log(p); + +// using setTimeout we can execute code after the stack is empty +setTimeout(function(){ + console.log('the stack is now empty'); + console.log(p); +}); + +// logs, in order: +// Promise { <state>: "pending" } +// the stack is now empty +// Promise { <state>: "fulfilled", <value>: 33 }</pre> + +<h3 id="使用_Promise.race_–_setTimeout_的示例"><font face="Open Sans, sans-serif">使用 </font>Promise.race – setTimeout 的示例</h3> + +<pre class="brush: js notranslate">var p1 = new Promise(function(resolve, reject) { + setTimeout(resolve, 500, "one"); +}); +var p2 = new Promise(function(resolve, reject) { + setTimeout(resolve, 100, "two"); +}); + +Promise.race([p1, p2]).then(function(value) { + console.log(value); // "two" + // 两个都完成,但 p2 更快 +}); + +var p3 = new Promise(function(resolve, reject) { + setTimeout(resolve, 100, "three"); +}); +var p4 = new Promise(function(resolve, reject) { + setTimeout(reject, 500, "four"); +}); + +Promise.race([p3, p4]).then(function(value) { + console.log(value); // "three" + // p3 更快,所以它完成了 +}, function(reason) { + // 未被调用 +}); + +var p5 = new Promise(function(resolve, reject) { + setTimeout(resolve, 500, "five"); +}); +var p6 = new Promise(function(resolve, reject) { + setTimeout(reject, 100, "six"); +}); + +Promise.race([p5, p6]).then(function(value) { + // 未被调用 +}, function(reason) { + console.log(reason); // "six" + // p6 更快,所以它失败了 +}); +</pre> + +<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.race', 'Promise.race')}}</td> + <td>{{Spec2('ES2015')}}</td> + <td>Initial definition in an ECMA standard.</td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-promise.race', 'Promise.race')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容">浏览器兼容</h2> + +<p class="hidden">The compatibility table in this page is generated from structured data. If you'd like to contribute to the data, please check out <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</p> + +<p>{{Compat("javascript.builtins.Promise.race")}}</p> + +<h2 id="相关链接">相关链接</h2> + +<ul> + <li>{{jsxref("Promise")}}</li> + <li>{{jsxref("Promise.all()")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/global_objects/promise/reject/index.html b/files/zh-cn/web/javascript/reference/global_objects/promise/reject/index.html new file mode 100644 index 0000000000..f5a8f82156 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/promise/reject/index.html @@ -0,0 +1,78 @@ +--- +title: Promise.reject() +slug: Web/JavaScript/Reference/Global_Objects/Promise/reject +tags: + - ECAMScript 2015 + - JavaScript + - Method + - Promise +translation_of: Web/JavaScript/Reference/Global_Objects/Promise/reject +--- +<div>{{JSRef}}</div> + +<p><code><strong>Promise.reject()</strong></code>方法返回一个带有拒绝原因的<code>Promise</code>对象。</p> + +<p>{{EmbedInteractiveExample("pages/js/promise-reject.html")}}</p> + +<h2 id="Syntax" name="Syntax">语法</h2> + +<pre class="syntaxbox"><var>Promise.reject(reason)</var>;</pre> + +<h3 id="参数">参数</h3> + +<dl> + <dt>reason</dt> + <dd>表示<code>Promise</code>被拒绝的原因。</dd> +</dl> + +<h3 id="返回值">返回值</h3> + +<dl> + <dd>一个给定原因了的被拒绝的 {{jsxref("Promise")}}。</dd> +</dl> + +<h2 id="Description" name="Description">描述</h2> + +<p><font face="Open Sans, sans-serif">静态函数</font><code>Promise.reject</code>返回一个被拒绝的<code>Promise对象</code>。通过使用{{jsxref("Error")}}的实例获取错误原因<code>reason</code>对调试和选择性错误捕捉很有帮助。</p> + +<h2 id="示例">示例</h2> + +<h3 id="使用静态Promise.reject方法">使用静态<code>Promise.reject()</code>方法</h3> + +<pre><code>Promise.reject(new Error('fail')).then(function() { + // not called +}, function(error) { + console.error(error); // Stacktrace +});</code></pre> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">规范</th> + <th scope="col">状态</th> + <th scope="col">备注</th> + </tr> + <tr> + <td>{{SpecName('ES2015', '#sec-promise.reject', 'Promise.reject')}}</td> + <td>{{Spec2('ES2015')}}</td> + <td>ECMA规范的首次定义</td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-promise.reject', 'Promise.reject')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + +<p>{{Compat("javascript.builtins.Promise.reject")}}</p> + +<h2 id="参见">参见</h2> + +<ul> + <li>{{jsxref("Promise")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/global_objects/promise/resolve/index.html b/files/zh-cn/web/javascript/reference/global_objects/promise/resolve/index.html new file mode 100644 index 0000000000..607fa09f36 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/promise/resolve/index.html @@ -0,0 +1,158 @@ +--- +title: Promise.resolve() +slug: Web/JavaScript/Reference/Global_Objects/Promise/resolve +tags: + - ECMAScript 2015 + - JavaScript + - Promise +translation_of: Web/JavaScript/Reference/Global_Objects/Promise/resolve +--- +<div>{{JSRef}}</div> + +<div><code><strong>Promise.resolve(value)</strong></code>方法返回一个以给定值解析后的{{jsxref("Promise")}} 对象。如果这个值是一个 promise ,那么将返回这个 promise ;如果这个值是thenable(即带有{{jsxref("Promise.then", "\"then\" ")}}方法),返回的promise会“跟随”这个thenable的对象,采用它的最终状态;否则返回的promise将以此值完成。<span style="font-size: 1rem; letter-spacing: -0.00278rem;">此函数将类promise对象的多层嵌套展平。</span></div> + +<div></div> + +<div></div> + +<div class="blockIndicator warning"> +<p>警告:不要在解析为自身的thenable 上调用<code>Promise.resolve</code>。这将导致无限递归,因为它试图展平无限嵌套的promise。一个例子是将它与Angular中的异步管道一起使用。在<a href="https://angular.io/guide/template-syntax#avoid-side-effects">此处</a>了解更多信息。</p> +</div> + +<div>{{EmbedInteractiveExample("pages/js/promise-resolve.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="Syntax" name="Syntax">语法</h2> + +<pre class="syntaxbox"><var>Promise.resolve(value)</var>; +</pre> + +<h3 id="参数">参数</h3> + +<dl> + <dt>value</dt> +</dl> + +<p>将被<code>Promise</code>对象解析的参数,也可以是一个<code>Promise</code>对象,或者是一个thenable。</p> + +<h3 id="返回值">返回值</h3> + +<p>返回一个带着给定值解析过的<code>Promise</code>对象,如果参数本身就是一个<code>Promise</code>对象,则直接返回这个<code>Promise</code>对象。</p> + +<h2 id="Description" name="Description">描述</h2> + +<p>静态方法 <code>Promise.resolve</code>返回一个解析过的<code>Promise</code>对象。</p> + +<h2 id="示例">示例</h2> + +<h3 id="使用静态Promise.resolve方法">使用静态<code>Promise.resolve</code>方法</h3> + +<pre class="brush: js">Promise.resolve("Success").then(function(value) { + console.log(value); // "Success" +}, function(value) { + // 不会被调用 +}); +</pre> + +<h3 id="resolve一个数组">resolve一个数组</h3> + +<pre class="brush: js">var p = Promise.resolve([1,2,3]); +p.then(function(v) { + console.log(v[0]); // 1 +}); +</pre> + +<h3 id="resolve另一个promise">resolve另一个promise</h3> + +<pre class="brush: js">var original = Promise.resolve(33); +var cast = Promise.resolve(original); +cast.then(function(value) { + console.log('value: ' + value); +}); +console.log('original === cast ? ' + (original === cast)); + +/* +* 打印顺序如下,这里有一个同步异步先后执行的区别 +* original === cast ? true +* value: 33 +*/</pre> + +<p>日志顺序颠倒其实是由于异步地调用<code>then</code> 方法。在<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then#Return_value">这里</a>查看<code>then</code> 是如何工作的。</p> + +<h3 id="resolve_thenable_并抛出错误">resolve thenable 并抛出错误</h3> + +<pre class="brush: js">// Resolve一个thenable对象 +var p1 = Promise.resolve({ + then: function(onFulfill, onReject) { onFulfill("fulfilled!"); } +}); +console.log(p1 instanceof Promise) // true, 这是一个Promise对象 + +p1.then(function(v) { + console.log(v); // 输出"fulfilled!" + }, function(e) { + // 不会被调用 +}); + +// Thenable在callback之前抛出异常 +// Promise rejects +var thenable = { then: function(resolve) { + throw new TypeError("Throwing"); + resolve("Resolving"); +}}; + +var p2 = Promise.resolve(thenable); +p2.then(function(v) { + // 不会被调用 +}, function(e) { + console.log(e); // TypeError: Throwing +}); + +// Thenable在callback之后抛出异常 +// Promise resolves +var thenable = { then: function(resolve) { + resolve("Resolving"); + throw new TypeError("Throwing"); +}}; + +var p3 = Promise.resolve(thenable); +p3.then(function(v) { + console.log(v); // 输出"Resolving" +}, function(e) { + // 不会被调用 +}); +</pre> + +<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('ES6', '#sec-promise.resolve', 'Promise.resolve')}}</td> + <td>{{Spec2('ES6')}}</td> + <td>ECMA标准中的首次定义</td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-promise.resolve', 'Promise.resolve')}}</td> + <td>{{Spec2('ES6')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + +<p class="hidden">The compatibility table in this page is generated from structured data. If you'd like to contribute to the data, please check out <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</p> + +<p>{{Compat("javascript.builtins.Promise.resolve")}}</p> + +<h2 id="参见">参见</h2> + +<ul> + <li>{{jsxref("Promise")}}</li> +</ul> diff --git a/files/zh-cn/web/javascript/reference/global_objects/promise/then/index.html b/files/zh-cn/web/javascript/reference/global_objects/promise/then/index.html new file mode 100644 index 0000000000..c41a74f379 --- /dev/null +++ b/files/zh-cn/web/javascript/reference/global_objects/promise/then/index.html @@ -0,0 +1,304 @@ +--- +title: Promise.prototype.then() +slug: Web/JavaScript/Reference/Global_Objects/Promise/then +tags: + - ECMAScript 2015 + - JavaScript + - Promise + - Prototype + - 方法 +translation_of: Web/JavaScript/Reference/Global_Objects/Promise/then +--- +<div>{{JSRef}}</div> + +<p><code><strong>then()</strong></code> 方法返回一个 {{domxref("Promise")}}。它最多需要有两个参数:Promise 的成功和失败情况的回调函数。</p> + +<div>{{EmbedInteractiveExample("pages/js/promise-then.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> + +<div class="note"> +<p>注意:如果忽略针对某个状态的回调函数参数,或者提供非函数 (nonfunction) 参数,那么 <code>then</code> 方法将会丢失关于该状态的回调函数信息,但是并不会产生错误。如果调用 <code>then</code> 的 <code>Promise</code> 的状态(fulfillment 或 rejection)发生改变,但是 <code>then</code> 中并没有关于这种状态的回调函数,那么 <code>then</code> 将创建一个没有经过回调函数处理的新 <code>Promise</code> 对象,这个新 <code>Promise</code> 只是简单地接受调用这个 <code>then</code> 的原 <code>Promise</code> 的终态作为它的终态。</p> +</div> + +<h2 id="语法">语法</h2> + +<pre class="syntaxbox"><var>p.then(onFulfilled[, onRejected])</var>; + +p.then(value => { + // fulfillment +}, reason => { + // rejection +}); +</pre> + +<h3 id="参数">参数</h3> + +<dl> + <dt><code>onFulfilled</code> {{optional_inline}}</dt> + <dd>当 Promise 变成接受状态(fulfilled)时调用的{{jsxref("Function", "函数")}}。该函数有一个参数,即接受的最终结果(the fulfillment value)。如果该参数不是函数,则会在内部被替换为 <code>(x) => x</code>,即原样返回 promise 最终结果的函数</dd> + <dt><code>onRejected</code> {{optional_inline}}</dt> + <dd>当 Promise 变成拒绝状态(rejected)时调用的{{jsxref("Function", "函数")}}。该函数有一个参数,即拒绝的原因(<code>rejection reason</code>)。 如果该参数不是函数,则会在内部被替换为一个 "Thrower" 函数 (it throws an error it received as argument)。</dd> +</dl> + +<h3 id="返回值">返回值</h3> + +<p>当一个 {{jsxref("Promise")}} 完成(fulfilled)或者失败(rejected)时,返回函数将被异步调用(由当前的线程循环来调度完成)。具体的返回值依据以下规则返回。如果 <code>then</code> 中的回调函数:</p> + +<ul> + <li>返回了一个值,那么 <code>then</code> 返回的 Promise 将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。</li> + <li>没有返回任何值,那么 <code>then</code> 返回的 Promise 将会成为接受状态,并且该接受状态的回调函数的参数值为 <code>undefined</code>。</li> + <li>抛出一个错误,那么 <code>then</code> 返回的 Promise 将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值。</li> + <li>返回一个已经是接受状态的 Promise,那么 <code>then</code> 返回的 Promise 也会成为接受状态,并且将那个 Promise 的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。</li> + <li>返回一个已经是拒绝状态的 Promise,那么 <code>then</code> 返回的 Promise 也会成为拒绝状态,并且将那个 Promise 的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。</li> + <li>返回一个未定状态(<code>pending</code>)的 Promise,那么 <code>then</code> 返回 Promise 的状态也是未定的,并且它的终态与那个 Promise 的终态相同;同时,它变为终态时调用的回调函数参数与那个 Promise 变为终态时的回调函数的参数是相同的。</li> +</ul> + +<p>下面是一个演示<code> then</code> 方法的同步性的例子。</p> + +<pre class="brush: js">// using a resolved promise, the 'then' block will be triggered instantly, +// but its handlers will be triggered asynchronously as demonstrated by the console.logs +const resolvedProm = Promise.resolve(33); + +let thenProm = resolvedProm.then(value => { + console.log("this gets called after the end of the main stack. the value received and returned is: " + value); + return value; +}); +// instantly logging the value of thenProm +console.log(thenProm); + +// using setTimeout we can postpone the execution of a function to the moment the stack is empty +setTimeout(() => { + console.log(thenProm); +}); + + +// 上面的代码会依次返回: +// Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined} +// "this gets called after the end of the main stack. the value received and returned is: 33" +// Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 33}</pre> + +<h2 id="描述">描述</h2> + +<p>由于 <code>then</code> 和 {{jsxref("Promise.prototype.catch()")}} 方法都会返回 promise,它们可以被<a href="/zh-CN/docs/Web/JavaScript/Guide/Using_promises#Chaining">链式调用</a>——这同时也是一种被称为<strong>复合</strong>( <em>composition) </em>的操作。</p> + +<h2 id="示例">示例</h2> + +<h3 id="使用_then_方法">使用 <code>then</code> 方法</h3> + +<pre class="brush: js">var p1 = new Promise((resolve, reject) => { + resolve('成功!'); + // or + // reject(new Error("出错了!")); +}); + +p1.then(value => { + console.log(value); // 成功! +}, reason => { + console.error(reason); // 出错了! +}); +</pre> + +<h3 id="链式调用">链式调用</h3> + +<p><font face="Open Sans, sans-serif"><code>then</code> 方法返回</font>一个 <code>Promise</code> 对象,其允许方法链。</p> + +<p>你可以传递一个匿名函数给 <code>then</code>,并且,如果它返回一个 <code>Promise</code>,一个等价的 <code>Promise</code> 将暴露给后续的方法链。下面的代码片段使用 <code>setTimout</code> 函数来模拟异步代码操作。</p> + +<pre class="brush: js">Promise.resolve("foo") + // 1. 接收 "foo" 并与 "bar" 拼接,并将其结果做为下一个 resolve 返回。 + .then(function(string) { + return new Promise(function(resolve, reject) { + setTimeout(function() { + string += 'bar'; + resolve(string); + }, 1); + }); + }) + // 2. 接收 "foobar", 放入一个异步函数中处理该字符串 + // 并将其打印到控制台中, 但是不将处理后的字符串返回到下一个。 + .then(function(string) { + setTimeout(function() { + string += 'baz'; + console.log(string); + }, 1) + return string; + }) + // 3. 打印本节中代码将如何运行的帮助消息, + // 字符串实际上是由上一个回调函数之前的那块异步代码处理的。 + .then(function(string) { + console.log("Last Then: oops... didn't bother to instantiate and return " + + "a promise in the prior then so the sequence may be a bit " + + "surprising"); + + // 注意 `string` 这时不会存在 'baz'。 + // 因为这是发生在我们通过setTimeout模拟的异步函数中。 + console.log(string); + }); + +// logs, in order: +// Last Then: oops... didn't bother to instantiate and return a promise in the prior then so the sequence may be a bit surprising +// foobar +// foobarbaz</pre> + +<p>当一个值只是从一个 <code>then</code> 内部返回时,它将等价地返回 <code>Promise.resolve(<由被调用的处理程序返回的值>)</code>。</p> + +<pre class="brush: js">var p2 = new Promise(function(resolve, reject) { + resolve(1); +}); + +p2.then(function(value) { + console.log(value); // 1 + return value + 1; +}).then(function(value) { + console.log(value + ' - A synchronous value works'); +}); + +p2.then(function(value) { + console.log(value); // 1 +}); +</pre> + +<p>如果函数抛出错误或返回一个拒绝的Promise,则 <code>then</code> 将返回一个拒绝的Promise。</p> + +<pre class="brush: js">Promise.resolve() + .then(() => { + // 使 .then() 返回一个 rejected promise + throw new Error('Oh no!'); + }) + .then(() => { + console.log('Not called.'); + }, error => { + console.error('onRejected function called: ' + error.message); + });</pre> + +<p>在其他情况下,一个 resolving Promise 会被返回。在下面的例子里,第一个 <code>then()</code> 会返回一个用 resolving Promise 包装的 <code>42</code>,即使之前的 Promise 是 rejected 的。</p> + +<pre class="brush: js">Promise.reject() + .then(() => 99, () => 42) // onRejected returns 42 which is wrapped in a resolving Promise + .then(solution => console.log('Resolved with ' + solution)); // Resolved with 42</pre> + +<p>实际上,捕获 rejected promise 的需求经常大于使用 <code>then</code> 的两种情况语法,比如下面这样的:</p> + +<pre class="brush: js">Promise.resolve() + .then(() => { + // 使 .then() 返回一个 rejected promise + throw new Error('Oh no!'); + }) + .catch(error => { + console.error('onRejected function called: ' + error.message); + }) + .then(() => { + console.log("I am always called even if the prior then's promise rejects"); + });</pre> + +<p>你也可以在另一个顶层函数上使用链式去实现基于 Promise API 的函数。</p> + +<pre class="brush: js">function fetch_current_data() { + // fetch() API 返回了一个 Promise. + // 这个函数提供了类似的API, + // 这个函数除了实现 Promise,它还能够完成更多的工作。 + return fetch('current-data.json').then(response => { + if (response.headers.get('content-type') != 'application/json') { + throw new TypeError(); + } + var j = response.json(); + // maybe do something with j + return j; // fulfillment value given to user of + // fetch_current_data().then() + }); +} +</pre> + +<p>如果 <code>onFulfilled</code> 返回了一个 promise,<code>then</code> 的返回值就会被 Promise resolved 或者 rejected。</p> + +<pre class="brush: js">function resolveLater(resolve, reject) { + setTimeout(function() { + resolve(10); + }, 1000); +} +function rejectLater(resolve, reject) { + setTimeout(function() { + reject(new Error('Error')); + }, 1000); +} + +var p1 = Promise.resolve('foo'); +var p2 = p1.then(function() { + // Return promise here, that will be resolved to 10 after 1 second + return new Promise(resolveLater); +}); +p2.then(function(v) { + console.log('resolved', v); // "resolved", 10 +}, function(e) { + // not called + console.error('rejected', e); +}); + +var p3 = p1.then(function() { + // Return promise here, that will be rejected with 'Error' after 1 second + return new Promise(rejectLater); +}); +p3.then(function(v) { + // not called + console.log('resolved', v); +}, function(e) { + console.error('rejected', e); // "rejected", 'Error' +}); +</pre> + +<h3 id="基于_promise_的_domxrefwindow.setImmediate_polyfill">基于 promise 的 {{domxref("window.setImmediate")}} polyfill</h3> + +<p>Using a {{jsxref("Function.prototype.bind()")}} <code>Reflect.apply</code> ({{jsxref("Reflect.apply()")}}) method to create a (non-cancellable) setImmediate-style function.</p> + +<pre class="brush: js">const nextTick = (() => { + const noop = () => {}; // literally + const nextTickPromise = () => Promise.resolve().then(noop); + + const rfab = Reflect.apply.bind; // (thisArg, fn, thisArg, [...args]) + const nextTick = (fn, ...args) => ( + fn !== undefined + ? Promise.resolve(args).then(rfab(null, fn, null)) + : nextTickPromise(), + undefined + ); + nextTick.ntp = nextTickPromise; + + return nextTick; +})(); +</pre> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">规范</th> + <th scope="col">状态</th> + <th scope="col">备注</th> + </tr> + <tr> + <td>{{SpecName('ES2015', '#sec-promise.prototype.then', 'Promise.prototype.then')}}</td> + <td>{{Spec2('ES2015')}}</td> + <td>ECMA 标准中的首次定义。</td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-promise.prototype.then', 'Promise.prototype.then')}}</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.then")}}</p> + +<h2 id="参见">参见</h2> + +<ul> + <li>{{jsxref("Promise")}}</li> + <li>{{jsxref("Promise.prototype.catch()")}}</li> +</ul> |
