aboutsummaryrefslogtreecommitdiff
path: root/files/zh-cn/web/javascript/reference/global_objects/promise/then/index.html
diff options
context:
space:
mode:
authorPeter Bengtsson <mail@peterbe.com>2020-12-08 14:40:17 -0500
committerPeter Bengtsson <mail@peterbe.com>2020-12-08 14:40:17 -0500
commit33058f2b292b3a581333bdfb21b8f671898c5060 (patch)
tree51c3e392513ec574331b2d3f85c394445ea803c6 /files/zh-cn/web/javascript/reference/global_objects/promise/then/index.html
parent8b66d724f7caf0157093fb09cfec8fbd0c6ad50a (diff)
downloadtranslated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.gz
translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.bz2
translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.zip
initial commit
Diffstat (limited to 'files/zh-cn/web/javascript/reference/global_objects/promise/then/index.html')
-rw-r--r--files/zh-cn/web/javascript/reference/global_objects/promise/then/index.html304
1 files changed, 304 insertions, 0 deletions
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 =&gt; {
+ // fulfillment
+}, reason =&gt; {
+ // rejection
+});
+</pre>
+
+<h3 id="参数">参数</h3>
+
+<dl>
+ <dt><code>onFulfilled</code> {{optional_inline}}</dt>
+ <dd>当 Promise 变成接受状态(fulfilled)时调用的{{jsxref("Function", "函数")}}。该函数有一个参数,即接受的最终结果(the fulfillment  value)。如果该参数不是函数,则会在内部被替换为 <code>(x) =&gt; 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 =&gt; {
+ 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(() =&gt; {
+ 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) =&gt; {
+ resolve('成功!');
+ // or
+ // reject(new Error("出错了!"));
+});
+
+p1.then(value =&gt; {
+ console.log(value); // 成功!
+}, reason =&gt; {
+ 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(&lt;由被调用的处理程序返回的值&gt;)</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(() =&gt; {
+ // 使 .then() 返回一个 rejected promise
+ throw new Error('Oh no!');
+ })
+ .then(() =&gt; {
+ console.log('Not called.');
+ }, error =&gt; {
+ 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(() =&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</pre>
+
+<p>实际上,捕获 rejected promise 的需求经常大于使用 <code>then</code> 的两种情况语法,比如下面这样的:</p>
+
+<pre class="brush: js">Promise.resolve()
+ .then(() =&gt; {
+ // 使 .then() 返回一个 rejected promise
+ throw new Error('Oh no!');
+ })
+ .catch(error =&gt; {
+ console.error('onRejected function called: ' + error.message);
+ })
+ .then(() =&gt; {
+ 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 =&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()
+ });
+}
+</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 = (() =&gt; {
+ const noop = () =&gt; {}; // literally
+ const nextTickPromise = () =&gt; Promise.resolve().then(noop);
+
+ const rfab = Reflect.apply.bind; // (thisArg, fn, thisArg, [...args])
+ const nextTick = (fn, ...args) =&gt; (
+ 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>