@@ -33,27 +33,30 @@ function $Resolve( $q, $injector) {
33
33
* <pre>
34
34
* $resolve.resolve(invocables, locals, parent, self)
35
35
* </pre>
36
- * but the former is more efficient (in fact `resolve` just calls `study`
36
+ * but the former is more efficient (in fact `resolve` just calls `study`
37
37
* internally).
38
38
*
39
39
* @param {object } invocables Invocable objects
40
40
* @return {function } a function to pass in locals, parent and self
41
41
*/
42
42
this . study = function ( invocables ) {
43
43
if ( ! isObject ( invocables ) ) throw new Error ( "'invocables' must be an object" ) ;
44
-
44
+
45
45
// Perform a topological sort of invocables to build an ordered plan
46
46
var plan = [ ] , cycle = [ ] , visited = { } ;
47
+
47
48
function visit ( value , key ) {
49
+
48
50
if ( visited [ key ] === VISIT_DONE ) return ;
49
-
51
+
50
52
cycle . push ( key ) ;
53
+
51
54
if ( visited [ key ] === VISIT_IN_PROGRESS ) {
52
55
cycle . splice ( 0 , cycle . indexOf ( key ) ) ;
53
56
throw new Error ( "Cyclic dependency: " + cycle . join ( " -> " ) ) ;
54
57
}
55
58
visited [ key ] = VISIT_IN_PROGRESS ;
56
-
59
+
57
60
if ( isString ( value ) ) {
58
61
plan . push ( key , [ function ( ) { return $injector . get ( value ) ; } ] , NO_DEPENDENCIES ) ;
59
62
} else {
@@ -63,61 +66,59 @@ function $Resolve( $q, $injector) {
63
66
} ) ;
64
67
plan . push ( key , value , params ) ;
65
68
}
66
-
69
+
67
70
cycle . pop ( ) ;
68
71
visited [ key ] = VISIT_DONE ;
69
72
}
73
+
70
74
forEach ( invocables , visit ) ;
71
75
invocables = cycle = visited = null ; // plan is all that's required
72
-
76
+
73
77
function isResolve ( value ) {
74
78
return isObject ( value ) && value . then && value . $$promises ;
75
79
}
76
-
80
+
77
81
return function ( locals , parent , self ) {
78
82
if ( isResolve ( locals ) && self === undefined ) {
79
83
self = parent ; parent = locals ; locals = null ;
80
84
}
81
85
if ( ! locals ) locals = NO_LOCALS ;
82
- else if ( ! isObject ( locals ) ) {
83
- throw new Error ( "'locals' must be an object" ) ;
84
- }
86
+ else if ( ! isObject ( locals ) ) throw new Error ( "'locals' must be an object" ) ;
87
+
85
88
if ( ! parent ) parent = NO_PARENT ;
86
- else if ( ! isResolve ( parent ) ) {
87
- throw new Error ( "'parent' must be a promise returned by $resolve.resolve()" ) ;
88
- }
89
-
89
+ else if ( ! isResolve ( parent ) ) throw new Error ( "'parent' must be a promise returned by $resolve.resolve()" ) ;
90
+
90
91
// To complete the overall resolution, we have to wait for the parent
91
92
// promise and for the promise for each invokable in our plan.
92
93
var resolution = $q . defer ( ) ,
93
94
result = resolution . promise ,
94
95
promises = result . $$promises = { } ,
95
96
values = extend ( { } , locals ) ,
96
- wait = 1 + plan . length / 3 ,
97
+ wait = 1 + plan . length / 3 ,
97
98
merged = false ;
98
-
99
+
99
100
function done ( ) {
100
101
// Merge parent values we haven't got yet and publish our own $$values
101
102
if ( ! -- wait ) {
102
- if ( ! merged ) merge ( values , parent . $$values ) ;
103
+ if ( ! merged ) merge ( values , parent . $$values ) ;
103
104
result . $$values = values ;
104
105
result . $$promises = true ; // keep for isResolve()
105
106
delete result . $$inheritedValues ;
106
107
resolution . resolve ( values ) ;
107
108
}
108
109
}
109
-
110
+
110
111
function fail ( reason ) {
111
112
result . $$failure = reason ;
112
113
resolution . reject ( reason ) ;
113
114
}
114
-
115
+
115
116
// Short-circuit if parent has already failed
116
117
if ( isDefined ( parent . $$failure ) ) {
117
118
fail ( parent . $$failure ) ;
118
119
return result ;
119
120
}
120
-
121
+
121
122
if ( parent . $$inheritedValues ) {
122
123
merge ( values , parent . $$inheritedValues ) ;
123
124
}
@@ -135,13 +136,13 @@ function $Resolve( $q, $injector) {
135
136
extend ( promises , parent . $$promises ) ;
136
137
parent . then ( done , fail ) ;
137
138
}
138
-
139
+
139
140
// Process each invocable in the plan, but ignore any where a local of the same name exists.
140
- for ( var i = 0 , ii = plan . length ; i < ii ; i += 3 ) {
141
+ for ( var i = 0 , ii = plan . length ; i < ii ; i += 3 ) {
141
142
if ( locals . hasOwnProperty ( plan [ i ] ) ) done ( ) ;
142
- else invoke ( plan [ i ] , plan [ i + 1 ] , plan [ i + 2 ] ) ;
143
+ else invoke ( plan [ i ] , plan [ i + 1 ] , plan [ i + 2 ] ) ;
143
144
}
144
-
145
+
145
146
function invoke ( key , invocable , params ) {
146
147
// Create a deferred for this invocation. Failures will propagate to the resolution as well.
147
148
var invocation = $q . defer ( ) , waitParams = 0 ;
@@ -176,65 +177,65 @@ function $Resolve( $q, $injector) {
176
177
// Publish promise synchronously; invocations further down in the plan may depend on it.
177
178
promises [ key ] = invocation . promise ;
178
179
}
179
-
180
+
180
181
return result ;
181
182
} ;
182
183
} ;
183
-
184
+
184
185
/**
185
186
* @ngdoc function
186
187
* @name ui.router.util.$resolve#resolve
187
188
* @methodOf ui.router.util.$resolve
188
189
*
189
190
* @description
190
- * Resolves a set of invocables. An invocable is a function to be invoked via
191
- * `$injector.invoke()`, and can have an arbitrary number of dependencies.
191
+ * Resolves a set of invocables. An invocable is a function to be invoked via
192
+ * `$injector.invoke()`, and can have an arbitrary number of dependencies.
192
193
* An invocable can either return a value directly,
193
- * or a `$q` promise. If a promise is returned it will be resolved and the
194
- * resulting value will be used instead. Dependencies of invocables are resolved
194
+ * or a `$q` promise. If a promise is returned it will be resolved and the
195
+ * resulting value will be used instead. Dependencies of invocables are resolved
195
196
* (in this order of precedence)
196
197
*
197
198
* - from the specified `locals`
198
199
* - from another invocable that is part of this `$resolve` call
199
- * - from an invocable that is inherited from a `parent` call to `$resolve`
200
+ * - from an invocable that is inherited from a `parent` call to `$resolve`
200
201
* (or recursively
201
202
* - from any ancestor `$resolve` of that parent).
202
203
*
203
- * The return value of `$resolve` is a promise for an object that contains
204
+ * The return value of `$resolve` is a promise for an object that contains
204
205
* (in this order of precedence)
205
206
*
206
207
* - any `locals` (if specified)
207
208
* - the resolved return values of all injectables
208
209
* - any values inherited from a `parent` call to `$resolve` (if specified)
209
210
*
210
- * The promise will resolve after the `parent` promise (if any) and all promises
211
- * returned by injectables have been resolved. If any invocable
212
- * (or `$injector.invoke`) throws an exception, or if a promise returned by an
213
- * invocable is rejected, the `$resolve` promise is immediately rejected with the
214
- * same error. A rejection of a `parent` promise (if specified) will likewise be
215
- * propagated immediately. Once the `$resolve` promise has been rejected, no
211
+ * The promise will resolve after the `parent` promise (if any) and all promises
212
+ * returned by injectables have been resolved. If any invocable
213
+ * (or `$injector.invoke`) throws an exception, or if a promise returned by an
214
+ * invocable is rejected, the `$resolve` promise is immediately rejected with the
215
+ * same error. A rejection of a `parent` promise (if specified) will likewise be
216
+ * propagated immediately. Once the `$resolve` promise has been rejected, no
216
217
* further invocables will be called.
217
- *
218
+ *
218
219
* Cyclic dependencies between invocables are not permitted and will caues `$resolve`
219
- * to throw an error. As a special case, an injectable can depend on a parameter
220
- * with the same name as the injectable, which will be fulfilled from the `parent`
221
- * injectable of the same name. This allows inherited values to be decorated.
220
+ * to throw an error. As a special case, an injectable can depend on a parameter
221
+ * with the same name as the injectable, which will be fulfilled from the `parent`
222
+ * injectable of the same name. This allows inherited values to be decorated.
222
223
* Note that in this case any other injectable in the same `$resolve` with the same
223
224
* dependency would see the decorated value, not the inherited value.
224
225
*
225
- * Note that missing dependencies -- unlike cyclic dependencies -- will cause an
226
- * (asynchronous) rejection of the `$resolve` promise rather than a (synchronous)
226
+ * Note that missing dependencies -- unlike cyclic dependencies -- will cause an
227
+ * (asynchronous) rejection of the `$resolve` promise rather than a (synchronous)
227
228
* exception.
228
229
*
229
- * Invocables are invoked eagerly as soon as all dependencies are available.
230
+ * Invocables are invoked eagerly as soon as all dependencies are available.
230
231
* This is true even for dependencies inherited from a `parent` call to `$resolve`.
231
232
*
232
- * As a special case, an invocable can be a string, in which case it is taken to
233
- * be a service name to be passed to `$injector.get()`. This is supported primarily
234
- * for backwards-compatibility with the `resolve` property of `$routeProvider`
233
+ * As a special case, an invocable can be a string, in which case it is taken to
234
+ * be a service name to be passed to `$injector.get()`. This is supported primarily
235
+ * for backwards-compatibility with the `resolve` property of `$routeProvider`
235
236
* routes.
236
237
*
237
- * @param {object } invocables functions to invoke or
238
+ * @param {object } invocables functions to invoke or
238
239
* `$injector` services to fetch.
239
240
* @param {object } locals values to make available to the injectables
240
241
* @param {object } parent a promise returned by another call to `$resolve`.
0 commit comments