]> git.proxmox.com Git - extjs.git/blame - extjs/packages/core/src/promise/Deferred.js
add extjs 6.0.1 sources
[extjs.git] / extjs / packages / core / src / promise / Deferred.js
CommitLineData
6527f429
DM
1/*\r
2 Ext.promise.Deferred adapted from:\r
3 [DeftJS](https://github.com/deftjs/deftjs5)\r
4 Copyright (c) 2012-2013 [DeftJS Framework Contributors](http://deftjs.org)\r
5 Open source under the [MIT License](http://en.wikipedia.org/wiki/MIT_License).\r
6 */\r
7\r
8/**\r
9 * Deferreds are the mechanism used to create new Promises. A Deferred has a single\r
10 * associated Promise that can be safely returned to external consumers to ensure they do\r
11 * not interfere with the resolution or rejection of the deferred operation.\r
12 *\r
13 * A Deferred is typically used within the body of a function that performs an asynchronous\r
14 * operation. When that operation succeeds, the Deferred should be resolved; if that\r
15 * operation fails, the Deferred should be rejected.\r
16 *\r
17 * Each Deferred has an associated Promise. A Promise delegates `then` calls to its\r
18 * Deferred's `then` method. In this way, access to Deferred operations are divided between\r
19 * producer (Deferred) and consumer (Promise) roles.\r
20 *\r
21 * When a Deferred's `resolve` method is called, it fulfills with the optionally specified\r
22 * value. If `resolve` is called with a then-able (i.e.a Function or Object with a `then`\r
23 * function, such as another Promise) it assimilates the then-able's result; the Deferred\r
24 * provides its own `resolve` and `reject` methods as the onFulfilled or onRejected\r
25 * arguments in a call to that then-able's `then` function. If an error is thrown while\r
26 * calling the then-able's `then` function (prior to any call back to the specified\r
27 * `resolve` or `reject` methods), the Deferred rejects with that error. If a Deferred's\r
28 * `resolve` method is called with its own Promise, it rejects with a TypeError.\r
29 *\r
30 * When a Deferred's `reject` method is called, it rejects with the optionally specified\r
31 * reason.\r
32 *\r
33 * Each time a Deferred's `then` method is called, it captures a pair of optional\r
34 * onFulfilled and onRejected callbacks and returns a Promise of the Deferred's future\r
35 * value as transformed by those callbacks.\r
36 *\r
37 * @private\r
38 * @since 6.0.0\r
39 */\r
40Ext.define('Ext.promise.Deferred', {\r
41 requires: [\r
42 'Ext.promise.Consequence'\r
43 ],\r
44\r
45 /**\r
46 * @property {Ext.promise.Promise} promise Promise of the future value of this Deferred.\r
47 */\r
48 promise: null,\r
49\r
50 /**\r
51 * @property {Ext.promise.Consequence[]} consequences Pending Consequences chained to this Deferred.\r
52 *\r
53 * @private\r
54 */\r
55 consequences: [],\r
56\r
57 /**\r
58 * @property {Boolean} completed Indicates whether this Deferred has been completed.\r
59 *\r
60 * @private\r
61 */\r
62 completed: false,\r
63\r
64 /**\r
65 * @property {String} completeAction The completion action (i.e. 'fulfill' or 'reject').\r
66 *\r
67 * @private\r
68 */\r
69 completionAction: null,\r
70\r
71 /**\r
72 * @property {Mixed} completionValue The completion value (i.e. resolution value or rejection error).\r
73 *\r
74 * @private\r
75 */\r
76 completionValue: null,\r
77\r
78 constructor: function() {\r
79 var me = this;\r
80\r
81 me.promise = new Ext.promise.Promise(me);\r
82 me.consequences = [];\r
83 me.completed = false;\r
84 me.completionAction = null;\r
85 me.completionValue = null;\r
86 },\r
87\r
88 /**\r
89 * Used to specify onFulfilled and onRejected callbacks that will be\r
90 * notified when the future value becomes available.\r
91 *\r
92 * Those callbacks can subsequently transform the value that was\r
93 * fulfilled or the error that was rejected. Each call to `then`\r
94 * returns a new Promise of that transformed value; i.e., a Promise\r
95 * that is fulfilled with the callback return value or rejected with\r
96 * any error thrown by the callback.\r
97 *\r
98 * @param {Function} [onFulfilled] Callback to execute to transform a fulfillment value.\r
99 * @param {Function} [onRejected] Callback to execute to transform a rejection reason.\r
100 * @param {Function} [onProgress] Callback to execute to transform a progress value.\r
101 *\r
102 * @return Promise that is fulfilled with the callback return value or rejected with\r
103 * any error thrown by the callback.\r
104 */\r
105 then: function(onFulfilled, onRejected, onProgress) {\r
106 var me = this,\r
107 consequence = new Ext.promise.Consequence(onFulfilled, onRejected, onProgress);\r
108\r
109 if (me.completed) {\r
110 consequence.trigger(me.completionAction, me.completionValue);\r
111 }\r
112 else {\r
113 me.consequences.push(consequence);\r
114 }\r
115\r
116 return consequence.promise;\r
117 },\r
118\r
119 /**\r
120 * Resolve this Deferred with the (optional) specified value.\r
121 *\r
122 * If called with a then-able (i.e.a Function or Object with a `then`\r
123 * function, such as another Promise) it assimilates the then-able's\r
124 * result; the Deferred provides its own `resolve` and `reject` methods\r
125 * as the onFulfilled or onRejected arguments in a call to that\r
126 * then-able's `then` function. If an error is thrown while calling\r
127 * the then-able's `then` function (prior to any call back to the\r
128 * specified `resolve` or `reject` methods), the Deferred rejects with\r
129 * that error. If a Deferred's `resolve` method is called with its own\r
130 * Promise, it rejects with a TypeError.\r
131 *\r
132 * Once a Deferred has been fulfilled or rejected, it is considered to be complete\r
133 * and subsequent calls to `resolve` or `reject` are ignored.\r
134 *\r
135 * @param {Mixed} value Value to resolve as either a fulfillment value or rejection\r
136 * reason.\r
137 */\r
138 resolve: function(value) {\r
139 var me = this,\r
140 isHandled, thenFn;\r
141\r
142 if (me.completed) {\r
143 return;\r
144 }\r
145\r
146 try {\r
147 if (value === me.promise) {\r
148 throw new TypeError('A Promise cannot be resolved with itself.');\r
149 }\r
150\r
151 if ((Ext.isObject(value) || Ext.isFunction(value)) &&\r
152 Ext.isFunction(thenFn = value.then)) {\r
153 isHandled = false;\r
154\r
155 try {\r
156 thenFn.call(value, function(value) {\r
157 if (!isHandled) {\r
158 isHandled = true;\r
159 me.resolve(value);\r
160 }\r
161 }, function(error) {\r
162 if (!isHandled) {\r
163 isHandled = true;\r
164 me.reject(error);\r
165 }\r
166 });\r
167 }\r
168 catch (e) {\r
169 if (!isHandled) {\r
170 me.reject(e);\r
171 }\r
172 }\r
173 }\r
174 else {\r
175 me.complete('fulfill', value);\r
176 }\r
177 }\r
178 catch (e) {\r
179 me.reject(e);\r
180 }\r
181 },\r
182\r
183 /**\r
184 * Reject this Deferred with the specified reason.\r
185 *\r
186 * Once a Deferred has been rejected, it is considered to be complete\r
187 * and subsequent calls to `resolve` or `reject` are ignored.\r
188 *\r
189 * @param {Error} reason Rejection reason.\r
190 */\r
191 reject: function(reason) {\r
192 if (this.completed) {\r
193 return;\r
194 }\r
195 \r
196 this.complete('reject', reason);\r
197 },\r
198\r
199 /**\r
200 * Updates progress for this Deferred, if it is still pending, triggering it to\r
201 * execute the `onProgress` callback and propagate the resulting transformed progress\r
202 * value to Deferreds that originate from this Deferred.\r
203 *\r
204 * @param {Mixed} progress The progress value.\r
205 */\r
206 update: function(progress) {\r
207 var consequences = this.consequences,\r
208 consequence, i, len;\r
209 \r
210 if (this.completed) {\r
211 return;\r
212 }\r
213 \r
214 for (i = 0, len = consequences.length; i < len; i++) {\r
215 consequence = consequences[i];\r
216 consequence.update(progress);\r
217 }\r
218 },\r
219\r
220 /**\r
221 * Complete this Deferred with the specified action and value.\r
222 *\r
223 * @param {String} action Completion action (i.e. 'fufill' or 'reject').\r
224 * @param {Mixed} value Fulfillment value or rejection reason.\r
225 *\r
226 * @private\r
227 */\r
228 complete: function(action, value) {\r
229 var me = this,\r
230 consequences = me.consequences,\r
231 consequence, i, len;\r
232\r
233 me.completionAction = action;\r
234 me.completionValue = value;\r
235 me.completed = true;\r
236\r
237 for (i = 0, len = consequences.length; i < len; i++) {\r
238 consequence = consequences[i];\r
239 consequence.trigger(me.completionAction, me.completionValue);\r
240 }\r
241\r
242 me.consequences = null;\r
243 }\r
244});\r