2019-04-21 11:50:48 +08:00

217 lines
13 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<article id="wikiArticle">
<div></div>
<p><code><strong>then()</strong></code> 方法返回一个  <a class="new" href="/zh-CN/docs/Web/API/Promise" rel="nofollow" title="此页面仍未被本地化, 期待您的翻译!"><code>Promise</code></a> 。它最多需要有两个参数Promise 的成功和失败情况的回调函数。</p>
<div><iframe class="interactive interactive-js" frameborder="0" height="250" src="https://interactive-examples.mdn.mozilla.net/pages/js/promise-then.html" width="100%"></iframe></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 class="external" href="https://github.com/mdn/interactive-examples" rel="noopener">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="Syntax" name="Syntax">语法</h2>
<pre><code class="language-javascript"><var>p.then(onFulfilled, onRejected)</var>;
p.then(function(value) {
// fulfillment
}, function(reason) {
// rejection
});
</code></pre>
<h3 id="参数">参数</h3>
<dl>
<dt>onFulfilled</dt>
<dd>当Promise变成接受状态fulfillment该参数作为回调函数被调用参考 <a href="Reference/Function" title="此页面仍未被本地化, 期待您的翻译!"><code>Function</code></a>。该函数有一个参数即接受的最终结果the fulfillment  value。如果传入的 <code>onFulfilled </code>参数类型不是函数,则会在内部被替换为<code>(x) =&gt; x </code>,即原样返回 promise 最终结果的函数</dd>
<dt>onRejected</dt>
<dd>当Promise变成拒绝状态rejection 该参数作为回调函数被调用参考 <a href="Reference/Function" title="此页面仍未被本地化, 期待您的翻译!"><code>Function</code></a>)。该函数有一个参数,,即拒绝的<code>原因the rejection reason</code></dd>
</dl>
<p> </p>
<pre>var p = new Promise((resolve, reject) =&gt; {
resolve('foo')
})
// 'bar' 不是函数,会在内部被替换为 (x) =&gt; x
p.then('bar').then((value) =&gt; {
console.log(value) // 'foo'
})</code></pre>
<p> </p>
<dl>
<dt>
<h3 id="返回值">返回值</h3>
<p>当一个<a href="Reference/Global_Objects/Promise" title="Promise 对象用于表示一个异步操作的最终状态完成或失败以及该异步操作的结果值。"><code>Promise</code></a>完成fulfilled或者失败rejected返回函数将被异步调用由当前的线程循环来调度完成。具体的返回值依据以下规则返回</p>
<ul>
<li>如果then中的回调函数返回一个值那么then返回的Promise将会成为接受状态并且将返回的值作为接受状态的回调函数的参数值。</li>
<li>如果then中的回调函数没有返回值那么then返回的Promise将会成为接受状态并且该接受状态的回调函数的参数值为 undefined。</li>
<li>如果then中的回调函数抛出一个错误那么then返回的Promise将会成为拒绝状态并且将抛出的错误作为拒绝状态的回调函数的参数值。</li>
<li>如果then中的回调函数返回一个已经是接受状态的Promise那么then返回的Promise也会成为接受状态并且将那个Promise的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。</li>
<li>如果then中的回调函数返回一个已经是拒绝状态的Promise那么then返回的Promise也会成为拒绝状态并且将那个Promise的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。</li>
<li>如果then中的回调函数返回一个未定状态pending的Promise那么then返回Promise的状态也是未定的并且它的终态与那个Promise的终态相同同时它变为终态时调用的回调函数参数与那个Promise变为终态时的回调函数的参数是相同的。</li>
</ul>
</dt>
</dl>
<h2 id="Description" name="Description">描述</h2>
<p>由于 <code>then</code> 和 <a href="Reference/Global_Objects/Promise/catch" title="catch() 方法返回一个Promise并且处理拒绝的情况。它的行为与调用Promise.prototype.then(undefined, onRejected) 相同。 (事实上, calling obj.catch(onRejected) 内部calls obj.then(undefined, onRejected))."><code>Promise.prototype.catch()</code></a> 方法都会返回 promise它们可以被链式调用 — 一种称为<strong>复合</strong> <em>composition </em>的操作.</p>
<h2 id="示例">示例</h2>
<h3 id="使用then方法"><code><font face="Open Sans, sans-serif">使用</font>then方法</code></h3>
<pre><code class="language-javascript">let p1 = new Promise(function(resolve, reject) {
resolve("Success!");
// or
// reject ("Error!");
});
p1.then(function(value) {
console.log(value); // Success!
}, function(reason) {
console.log(reason); // Error!
});
</code></pre>
<h3 id="链式调用">链式调用</h3>
<p><font face="Open Sans, sans-serif">then 方法返回</font>一个Promise 对象其允许方法链。</p>
<p>你可以传递一个 lambda 给 then 并且如果它返回一个 promise一个等价的 Promise 将暴露给后续的方法链。下面的代码片段使用 setTimout 函数来模拟异步代码操作。</p>
<pre><code class="language-javascript">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);
});</code></pre>
<p>当一个值只是从一个 lambda 内部返回时,它将有效地返回 Promise.resolve&lt;由被调用的处理程序返回的值&gt;)。</p>
<pre><code class="language-javascript">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 + "- This synchronous usage is virtually pointless"); // 2- This synchronous usage is virtually pointless
});
p2.then(function(value) {
console.log(value); // 1
});</code></pre>
<p>如果函数抛出错误或返回一个拒绝的Promise则调用将返回一个拒绝的Promise。</p>
<pre><code class="language-javascript">Promise.resolve()
.then( () =&gt; {
// 使 .then() 返回一个 rejected promise
throw 'Oh no!';
})
.then( () =&gt; {
console.log( 'Not called.' );
}, reason =&gt; {
console.error( 'onRejected function called: ', reason );
});</code></pre>
<p>在其他情况下,一个 resolving Promise 会被返回。在下面的例子里,第一个 then() 会返回一个用 resolving Promise 包装的 42即使之前的 Promise 是 rejected 的。</p>
<pre><code class="language-javascript">Promise.reject()
  .then( () =&gt; 99, () =&gt; 42 ) // onRejected returns 42 which is wrapped in a resolving Promise
  .then( solution =&gt; console.log( 'Resolved with ' + solution ) ); // Resolved with 42</code></pre>
<p>实际上,捕获 rejected promise 的需求经常大于使用 then 的两种情况语法,比如下面这样的:</p>
<pre><code class="language-javascript">Promise.resolve()
.then( () =&gt; {
// 使 .then() 返回一个 rejected promise
throw 'Oh no!';
})
.catch( reason =&gt; {
console.error( 'onRejected function called: ', reason );
})
.then( () =&gt; {
console.log( "I am always called even if the prior then's promise rejects" );
});</code></pre>
<p>你也可以在另一个顶层函数上使用链式去实现带有 Promise-based API 的函数。</p>
<pre><code class="language-javascript">function fetch_current_data() {
// fetch() API 返回了一个 Promise.
// 这个函数提供了类似的API
// 这个函数除了实现 Promise它还能够完成更多的工作。
return fetch('current-data.json').then((response) =&gt; {
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()
});
}</code></pre>
<p>如果 <code>onFulfilled</code> 返回了一个 promise<code>then</code> 的返回值就会被 Promise resolved或者rejected。</p>
<pre><code class="language-javascript">function resolveLater(resolve, reject) {
setTimeout(function () {
resolve(10);
}, 1000);
}
function rejectLater(resolve, reject) {
setTimeout(function () {
reject(20);
}, 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.log('rejected', e);
});
var p3 = p1.then(function() {
// Return promise here, that will be rejected with 20 after 1 second
return new Promise(rejectLater);
});
p3.then(function(v) {
// not called
console.log('resolved', v);
}, function(e) {
console.log('rejected', e); // "rejected", 20
});</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><a class="external" href="https://www.ecma-international.org/ecma-262/6.0/#sec-promise.prototype.then" hreflang="en" lang="en" rel="noopener">ECMAScript 2015 (6th Edition, ECMA-262)<br/><small lang="zh-CN">Promise.prototype.then</small></a></td>
<td><span class="spec-Standard">Standard</span></td>
<td>ECMA标准的首次定义</td>
</tr>
<tr>
<td><a class="external" href="https://tc39.github.io/ecma262/#sec-promise.prototype.then" hreflang="en" lang="en" rel="noopener">ECMAScript Latest Draft (ECMA-262)<br/><small lang="zh-CN">Promise.prototype.then</small></a></td>
<td><span class="spec-Draft">Draft</span></td>
<td> </td>
</tr>
</tbody>
</table>
<h2 id="浏览器兼容性">浏览器兼容性</h2>
<p>No compatibility data found. Please contribute data for "javascript/promise" (depth: Promise.prototype.then) to the <a class="external" href="https://github.com/mdn/browser-compat-data" rel="noopener">MDN compatibility data repository</a>.</p>
<p><br/>
<strong style="font-size: 2.143rem; font-weight: 700; letter-spacing: -1px; line-height: 1;">相关链接</strong></p>
<ul>
<li><a href="Reference/Global_Objects/Promise" title="Promise 对象用于表示一个异步操作的最终状态完成或失败以及该异步操作的结果值。"><code>Promise</code></a></li>
<li><a href="Reference/Global_Objects/Promise/catch" title="catch() 方法返回一个Promise并且处理拒绝的情况。它的行为与调用Promise.prototype.then(undefined, onRejected) 相同。 (事实上, calling obj.catch(onRejected) 内部calls obj.then(undefined, onRejected))."><code>Promise.prototype.catch()</code></a></li>
</ul>
</article>