diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
commit | 33058f2b292b3a581333bdfb21b8f671898c5060 (patch) | |
tree | 51c3e392513ec574331b2d3f85c394445ea803c6 /files/zh-cn/web/javascript/reference/global_objects/promise/then/index.html | |
parent | 8b66d724f7caf0157093fb09cfec8fbd0c6ad50a (diff) | |
download | translated-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.html | 304 |
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 => { + // 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> |