@@ -7,6 +7,7 @@ import {Resolvables, IOptions1} from "./interface";
7
7
8
8
import { ResolveContext } from "./resolveContext" ;
9
9
import { stringify } from "../common/strings" ;
10
+ import { isFunction } from "../common/predicates" ;
10
11
11
12
/**
12
13
* The basic building block for the resolve system.
@@ -48,61 +49,52 @@ export class Resolvable {
48
49
if ( token instanceof Resolvable ) {
49
50
extend ( this , token ) ;
50
51
} else {
52
+ if ( token == null || token == undefined ) throw new Error ( "new Resolvable(): token argument is required" ) ;
53
+ if ( ! isFunction ( resolveFn ) ) throw new Error ( "new Resolvable(): resolveFn argument must be a function" ) ;
54
+
51
55
this . token = token ;
52
56
this . resolveFn = resolveFn ;
53
- this . deps = deps ;
57
+ this . deps = deps || [ ] ;
54
58
this . data = data ;
55
59
this . resolved = data !== undefined ;
60
+ this . promise = this . resolved ? services . $q . when ( this . data ) : undefined ;
56
61
}
57
62
}
58
63
59
- // synchronous part:
60
- // - sets up the Resolvable's promise
61
- // - retrieves dependencies' promises
62
- // - returns promise for async part
63
-
64
- // asynchronous part:
65
- // - wait for dependencies promises to resolve
66
- // - invoke the resolveFn
67
- // - wait for resolveFn promise to resolve
68
- // - store unwrapped data
69
- // - resolve the Resolvable's promise
70
- resolveResolvable ( resolveContext : ResolveContext , options : IOptions1 = { } ) {
71
- let { deps, resolveFn} = this ;
72
-
73
- trace . traceResolveResolvable ( this , options ) ;
74
- // First, set up an overall deferred/promise for this Resolvable
75
- let deferred = services . $q . defer ( ) ;
76
- this . promise = deferred . promise ;
77
- // Load a map of all resolvables for this state from the context path
78
- // Omit the current Resolvable from the result, so we don't try to inject this into this
79
- let ancestorsByName : Resolvables = resolveContext . getResolvables ( null , { omitOwnLocals : [ this . token ] } ) ;
80
-
81
- // Limit the ancestors Resolvables map to only those that the current Resolvable fn's annotations depends on
82
- let depResolvables : Resolvables = < any > pick ( ancestorsByName , deps ) ;
83
-
84
- // Get promises (or synchronously invoke resolveFn) for deps
85
- let depPromises : any = map ( depResolvables , ( resolvable : Resolvable ) => resolvable . get ( resolveContext , options ) ) ;
86
-
87
- // Return a promise chain that waits for all the deps to resolve, then invokes the resolveFn passing in the
88
- // dependencies as locals, then unwraps the resulting promise's data.
89
- return services . $q . all ( depPromises ) . then ( locals => {
90
- try {
91
- let result = services . $injector . invoke ( resolveFn , null , locals ) ;
92
- deferred . resolve ( result ) ;
93
- } catch ( error ) {
94
- deferred . reject ( error ) ;
95
- }
96
- return this . promise ;
97
- } ) . then ( data => {
98
- this . data = data ;
99
- trace . traceResolvableResolved ( this , options ) ;
100
- return this . promise ;
101
- } ) ;
64
+ /**
65
+ * Asynchronously resolve this Resolvable's data
66
+ *
67
+ * Given a ResolveContext that this Resolvable is found in:
68
+ * Wait for this Resolvable's dependencies, then invoke this Resolvable's function
69
+ * and update the Resolvable's state
70
+ */
71
+ resolve ( resolveContext : ResolveContext , options : IOptions1 = { } ) {
72
+ let $q = services . $q ;
73
+ return this . promise = $q . when ( )
74
+ // Get all dependencies from ResolveContext and wait for them to be resolved
75
+ . then ( ( ) =>
76
+ $q . all ( resolveContext . getDependencies ( this ) . map ( r =>
77
+ r . get ( resolveContext , options ) ) ) )
78
+ // Invoke the resolve function passing the resolved dependencies
79
+ . then ( resolvedDeps =>
80
+ this . resolveFn . apply ( null , resolvedDeps ) )
81
+ // Wait for returned promise to resolve then update the Resolvable state
82
+ . then ( resolvedValue => {
83
+ this . data = resolvedValue ;
84
+ this . resolved = true ;
85
+ trace . traceResolvableResolved ( this , options ) ;
86
+ return this . data ;
87
+ } ) ;
102
88
}
103
89
90
+ /**
91
+ * Gets a promise for this Resolvable's data.
92
+ *
93
+ * Fetches the data and returns a promise.
94
+ * Returns the existing promise if it has already been fetched once.
95
+ */
104
96
get ( resolveContext : ResolveContext , options ?: IOptions1 ) : Promise < any > {
105
- return this . promise || this . resolveResolvable ( resolveContext , options ) ;
97
+ return this . promise || this . resolve ( resolveContext , options ) ;
106
98
}
107
99
108
100
toString ( ) {
0 commit comments