aboutsummaryrefslogtreecommitdiff
path: root/files/zh-cn/mozilla/javascript_code_modules/promise.jsm/promise/index.html
blob: 947fd3acdc5beb243e1e8bfd900885dd51a8bb13 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
---
title: Promise
slug: Mozilla/JavaScript_code_modules/Promise.jsm/Promise
translation_of: Mozilla/JavaScript_code_modules/Promise.jsm/Promise
---
<p><strong>Promise对象代表暂时不可用的值。</strong></p>

<p>一个已存在的promise引用可以通过不同的方式被接收,如作为异步API的返回值。一旦得到一个promise对象,就可以调用其 <a href="#then()" title="#then()"><code>then()</code></a> 方法,以在其值可用时或者出现异常时执行一个动作。</p>

<p>可以通过 <a href="https://developer.mozilla.org/zh-CN/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Promise$edit#Constructor" title="#Constructor"><code>new Promise()</code></a><code> </code>方法创建Promise对象,当使用一个已存在的Promise对象时,不需要引入 <a href="https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm" title="#defer()"><code>Promise.jsm</code></a> 模块。</p>

<p>promise内部状态可为以下三种之一:</p>

<ul>
 <li><strong>未完成状态(pending)</strong>,此时完成值还不可用,它是唯一一个能够转换为其他状态的状态。</li>
 <li><strong>已完成状态(fulfilled)</strong>,此时<em>完成值</em>可用,完成值与promise永久绑定,可为任意值,包括<code>undefined。</code></li>
 <li><strong>拒绝状态(rejected)</strong>,出现错误时,<em>拒绝理由</em>与promise永久绑定,可为任意值,包括<code>undefined</code>,一般情况下为 <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Error" title="/en-US/docs/JavaScript/Reference/Global_Objects/Error"><code>Error</code></a> 对象。</li>
</ul>

<div class="note">
<p><strong>备注: </strong>使用promise时,应该始终对异常(拒绝理由)进行处理或报告。如果你看见了"<strong>A promise chain failed to handle a rejection</strong>"的错误信息,你可能就需要检查你的代码。参见下面的 <a href="https://developer.mozilla.org/zh-CN/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Promise$edit#Handling_errors_and_common_pitfalls">异常处理和常见误区</a></p>
</div>

<h2 id="文档约定">文档约定</h2>

<p>文档规定,完成值的类型通过尖括号内的内容指定。如 <code style="font-style: normal;"><a href="/en-US/docs/JavaScript_OS.File/OS.File_for_the_main_thread#OS.File.exists()" title="/en-US/docs/JavaScript_OS.File/OS.File_for_the_main_thread#OS.File.exists()">OS.File.exists</a></code> 方法返回一个完成值类型为<code>boolean</code>的promise:</p>

<pre>Promise&lt;boolean&gt; exists(string path);
</pre>

<p>拒绝理由可能在function文档中单独规定,除非特别指定,一般使用 <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Error" title="/en-US/docs/JavaScript/Reference/Global_Objects/Error"><code>Error</code></a> 对象作为拒绝理由。</p>

<h2 id="方法概览">方法概览</h2>

<table>
 <tbody>
  <tr>
   <td><code>Promise <a href="https://developer.mozilla.org/zh-CN/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Promise$edit#then()">then</a>([optional] <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function" title="/en-US/docs/JavaScript/Reference/Global_Objects/Function">Function</a> onFulfill, </code><code>[optional] </code><code><a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function" title="/en-US/docs/JavaScript/Reference/Global_Objects/Function">Function</a> onReject</code><code>);</code></td>
  </tr>
  <tr>
   <td><code>Promise <a href="https://developer.mozilla.org/zh-CN/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Promise$edit#catch">catch</a>([optional] <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function">Function</a> onReject);</code></td>
  </tr>
 </tbody>
</table>

<h2 id="构造函数">构造函数</h2>

<p>创建一个新的promise,初始化为等待状态,并提供解决函数的引用,用于改变其状态。</p>

<pre><code>new Promise(executor);</code></pre>

<h3 id="参数">参数</h3>

<dl>
 <dt><code>executor</code></dt>
 <dd>
 <p>该函数会马上被调用,它带有两个参数的函数对象:</p>

 <p> </p>
 </dd>
 <dd>
 <pre><code>executor(resolve, reject);</code></pre>

 <p>构造函数直到执行完成才会返回。解决函数可以在任何时间被调用,在执行过程完成前后都可以,其目标是控制promise的最终状态。如果执行过程抛出异常,异常值会被传递到reject解决函数中。</p>
 </dd>
</dl>

<h3 id="解决函数">解决函数</h3>

<h4 id="resolve()">resolve()</h4>

<p>用特定值满足绑定的promise,或者把状态传递到一个已存在的promise。如果绑定的promise已经被解决(可能是一个值,也可能是一个rejection,或者是另一个promise),该方法不会做任何事。</p>

<div class="note">
<p><strong>备注:</strong> 调用该方法时,如果用一个pending状态的promise作为aValue参数,然后在该promise状态改变为fullfilled或者rejected前用另一个值再次调用,第二次调用将不会生效,因为这个绑定的promise已经被pending promise所解决了。</p>
</div>

<pre><code>void resolve(
  aValue
);</code></pre>

<h6 id="参数_2">参数</h6>

<dl>
 <dt><code>aValue</code>  可选</dt>
 <dd>如果这个值不是一个promise,包括  <code>undefined</code>, 它会变成绑定promise的实现值。如果这个值是promise,绑定promise会被传递的promise解决,并跟随所提供的promise的状态(包括任何未来的转变)。</dd>
</dl>

<h4 id="reject()">reject()</h4>

<p>用特定原因拒绝绑定的promise。如果promise已经被解决了,不管是值,拒绝,还是另一个promise,这个方法都不会做任何事。</p>

<pre><code>void reject(
  aReason
);</code></pre>

<h6 id="参数_3">参数</h6>

<dl>
 <dt><code>aReason</code> 可选</dt>
 <dd>绑定promise的拒绝原因。通常是一个 <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Error">Error</a> 对象,就像在异常处理那样,尽管理由也可以是 <code>undefined。</code></dd>
</dl>

<div class="note">
<p><strong>备注:</strong> 该参数不应该是promise。要说明一个被拒绝的promise,应该让拒绝原因等于被拒绝promise自身,而非其拒绝原因。</p>
</div>

<h2 id="方法">方法</h2>

<h3 id="then()">then()</h3>

<p><span style="line-height: 1.5;">一旦promise完成或被拒绝,就立即执行一个回调函数,并返回一个新的promise对象,新promise的状态取决于promise和传入的回调函数</span></p>

<div>回调函数始终会在<code>then</code>返回值后被调用,即使promise早已完成或已被拒绝。也可对多次调用同一个promise的<code>then</code>方法。所有的回调函数会按照其注册的顺序被调用。</div>

<p> </p>

<div class="warning">
<p><strong>警告</strong>: 如果 <code>onFulfill</code> 抛出异常,不会调用 <code>onReject</code> ,异常也不会被捕获和输出到控制台(你会看到一个promise chain失败错误),可以在返回的promise上注册一个错误处理函数,以处理在任一回调中出现的异常(使用 catch() 或者 then() ),来处理发生在任何一个注册回调函数的异常。</p>
</div>

<p> </p>

<div class="note">
<p><strong>注意</strong>:当多次调用同一个promise的then方法,所有注册的回调函数独立执行。如,当在一个回调函数中出现异常时,不会影响后面回调函数的执行。回调函数的结果只会对其注册所使用的then方法返回的promise产生影响,每一次调用then方法返回的都是不同的promise对象。</p>
</div>

<pre>Promise then(
  Function onFulfill,
  Function onReject
);
</pre>

<h6 id="参数_4">参数</h6>

<dl>
 <dt><code>onFulfill</code> {{optional_inline()}}</dt>
 <dd>当promise完成时,会调用该函数,并将完成值作为其唯一参数传入,该函数的输出会决定新的promise的状态。如果该参数不是函数(通常为<code>null</code>),则由then返回的新的promise的状态为已完成,且完成值与原promise相同</dd>
 <dt><code>onReject</code> {{optional_inline()}}</dt>
 <dd>
 <p>当promise被拒绝时,会调用该函数,并将拒绝理由作为其唯一参数传入,且该函数的输出会决定新的promise的状态。如果该参数不是函数(通常为<code>undefined</code>),则由<code>then</code>返回的新的promise的状态为拒绝,且拒绝理由与原promise相同。</p>
 </dd>
</dl>

<h6 id="返回值">返回值</h6>

<p>新的promise对象,初始状态为未完成,最终状态取决于回调函数的输出:</p>

<ul>
 <li>
  <div>如果返回的不是promise,包括<code>undefined</code>,则新promise的状态为已完成,并将该返回值作为其完成值,即使原promises被拒绝</div>
 </li>
 <li>
  <div><span style="line-height: 1.5;">如果抛出异常,则新的promise的状态为拒绝,并将该异常作为其拒绝理由,即使原promise已完成</span></div>
 </li>
 <li>
  <div><span style="line-height: 1.5;">如果返回promise,则新promise的最终状态与回调函数返回的promise状态相同。</span></div>
 </li>
</ul>

<div>
<h3 id="catch()"><a name="catch">catch()</a></h3>

<p>等价于调用<code>onFulfill参数为undefined的</code> <code>then()</code> 方法。如果你链式调用then( onFulfill ).catch( onReject ),onFulfill中抛出的异常会被捕捉并传递到onReject。</p>

<pre><code>Promise catch(
  Function onReject
);</code></pre>

<p>等价于以下调用:</p>

<pre><code>p.then(undefined, logError);
p.catch(logError);</code></pre>
</div>

<div> </div>

<h2 id="调试">调试</h2>

<p>按照设计,在不调用 <code style="font-style: normal;"><a href="#then()" title="#then()">then()</a></code>的情况下,promise的即时状态和值不能通过代码同步检测到。</p>

<p>为了有助于调试,只有当手动检查promise时,才能看到那些不能通过代码访问的特殊属性的信息(目前由于缺少复杂的语言或调试器的支持,属性名是随机生成的)。</p>

<p>这些代码可访问和可审查的属性有:</p>

<ul>
 <li><code><strong><span>{</span>{private:status}}</strong></code>: 0代表未完成,1代表已完成,2代表拒绝。</li>
 <li><code><strong><span>{</span>{private:value}}</strong></code>:完成值或拒绝理由,仅在promise已完成或已拒绝时有值。</li>
 <li><code><strong><span>{</span>{private:handlers}}</strong></code>: 对象数组,这些对象保存了对回调函数的引用,仅在未完成状态下可用。</li>
</ul>

<p style="text-align: center;"><img alt="Promise properties are visible in the debugger." src="https://mdn.mozillademos.org/files/6471/Promise-Debug-1.png" style="border-style: solid; border-width: 2px; height: 482px; margin-bottom: 15px; margin-top: 15px; width: 403px;"><img alt="Promise handlers can be watched from the Console." src="https://mdn.mozillademos.org/files/6473/Promise-Debug-2.png" style="border-style: solid; border-width: 2px; height: 161px; width: 977px;"></p>

<h2 id="示例">示例</h2>

<p id="如何抛出拒绝">请看 <a href="https://developer.mozilla.org/Mozilla/JavaScript_code_modules/Promise.jsm/Examples">示例</a> 页面.</p>

<h2 id="异常处理和常见误区">异常处理和常见误区</h2>

<p>promise应该报告未处理的错误,除非交给其他程序处理该错误。</p>

<pre class="brush: js">// ###### WRONG: Silently drops any rejection notified by "OS.File.Exists".
OS.File.exists(path).then(exists =&gt; { if (exists) myRead(path); });

// ###### WRONG: Silently drops any exception raised by "myRead".
OS.File.exists(path).then(exists =&gt; { if (exists) myRead(path); }, Components.utils.reportError);

// CORRECT (for example, might report the exception "myRead is not defined")
OS.File.exists(path).then(exists =&gt; { if (exists) myRead(path); })
                    .catch(null, Components.utils.reportError);

// CORRECT (the function returns a promise, and the caller will handle the rejection)
function myReadIfExists(path)
{
  return OS.File.exists(path).then(exists =&gt; { if (exists) myRead(path); });
}</pre>

<h2 id="参见">参见</h2>

<ul>
 <li><a href="/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm" title="/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm">Promise.jsm</a></li>
 <li><a href="/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Deferred" title="/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Deferred">Deferred</a></li>
 <li><a href="/en-US/docs/JavaScript_OS.File" title="/en-US/docs/JavaScript_OS.File">JavaScript OS.File</a></li>
 <li><a href="http://kryogenix.org/days/2013/12/12/promises-promises">Promises, Promises</a>: a useful simple explanation by Stuart Langridge</li>
 <li><a href="http://dom.spec.whatwg.org/#promises">WHATWG Living Standard</a></li>
</ul>