mirror of
https://github.com/wahyd4/Libr-mobile.git
synced 2026-08-16 16:28:29 +10:00
266 lines
10 KiB
HTML
266 lines
10 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>JSDoc: Source: resolve.js</title>
|
|
|
|
<script src="scripts/prettify/prettify.js"> </script>
|
|
<script src="scripts/prettify/lang-css.js"> </script>
|
|
<!--[if lt IE 9]>
|
|
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
|
<![endif]-->
|
|
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
|
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div id="main">
|
|
|
|
<h1 class="page-title">Source: resolve.js</h1>
|
|
|
|
|
|
|
|
|
|
|
|
<section>
|
|
<article>
|
|
<pre class="prettyprint source"><code>/**
|
|
* Service (`ui-util`). Manages resolution of (acyclic) graphs of promises.
|
|
* @module $resolve
|
|
* @requires $q
|
|
* @requires $injector
|
|
*/
|
|
$Resolve.$inject = ['$q', '$injector'];
|
|
function $Resolve( $q, $injector) {
|
|
|
|
var VISIT_IN_PROGRESS = 1,
|
|
VISIT_DONE = 2,
|
|
NOTHING = {},
|
|
NO_DEPENDENCIES = [],
|
|
NO_LOCALS = NOTHING,
|
|
NO_PARENT = extend($q.when(NOTHING), { $$promises: NOTHING, $$values: NOTHING });
|
|
|
|
|
|
/**
|
|
* Studies a set of invocables that are likely to be used multiple times.
|
|
* $resolve.study(invocables)(locals, parent, self)
|
|
* is equivalent to
|
|
* $resolve.resolve(invocables, locals, parent, self)
|
|
* but the former is more efficient (in fact `resolve` just calls `study` internally).
|
|
* See {@link module:$resolve/resolve} for details.
|
|
* @function
|
|
* @param {Object} invocables
|
|
* @return {Function}
|
|
*/
|
|
this.study = function (invocables) {
|
|
if (!isObject(invocables)) throw new Error("'invocables' must be an object");
|
|
|
|
// Perform a topological sort of invocables to build an ordered plan
|
|
var plan = [], cycle = [], visited = {};
|
|
function visit(value, key) {
|
|
if (visited[key] === VISIT_DONE) return;
|
|
|
|
cycle.push(key);
|
|
if (visited[key] === VISIT_IN_PROGRESS) {
|
|
cycle.splice(0, cycle.indexOf(key));
|
|
throw new Error("Cyclic dependency: " + cycle.join(" -> "));
|
|
}
|
|
visited[key] = VISIT_IN_PROGRESS;
|
|
|
|
if (isString(value)) {
|
|
plan.push(key, [ function() { return $injector.get(value); }], NO_DEPENDENCIES);
|
|
} else {
|
|
var params = $injector.annotate(value);
|
|
forEach(params, function (param) {
|
|
if (param !== key && invocables.hasOwnProperty(param)) visit(invocables[param], param);
|
|
});
|
|
plan.push(key, value, params);
|
|
}
|
|
|
|
cycle.pop();
|
|
visited[key] = VISIT_DONE;
|
|
}
|
|
forEach(invocables, visit);
|
|
invocables = cycle = visited = null; // plan is all that's required
|
|
|
|
function isResolve(value) {
|
|
return isObject(value) && value.then && value.$$promises;
|
|
}
|
|
|
|
return function (locals, parent, self) {
|
|
if (isResolve(locals) && self === undefined) {
|
|
self = parent; parent = locals; locals = null;
|
|
}
|
|
if (!locals) locals = NO_LOCALS;
|
|
else if (!isObject(locals)) {
|
|
throw new Error("'locals' must be an object");
|
|
}
|
|
if (!parent) parent = NO_PARENT;
|
|
else if (!isResolve(parent)) {
|
|
throw new Error("'parent' must be a promise returned by $resolve.resolve()");
|
|
}
|
|
|
|
// To complete the overall resolution, we have to wait for the parent
|
|
// promise and for the promise for each invokable in our plan.
|
|
var resolution = $q.defer(),
|
|
result = resolution.promise,
|
|
promises = result.$$promises = {},
|
|
values = extend({}, locals),
|
|
wait = 1 + plan.length/3,
|
|
merged = false;
|
|
|
|
function done() {
|
|
// Merge parent values we haven't got yet and publish our own $$values
|
|
if (!--wait) {
|
|
if (!merged) merge(values, parent.$$values);
|
|
result.$$values = values;
|
|
result.$$promises = true; // keep for isResolve()
|
|
resolution.resolve(values);
|
|
}
|
|
}
|
|
|
|
function fail(reason) {
|
|
result.$$failure = reason;
|
|
resolution.reject(reason);
|
|
}
|
|
|
|
// Short-circuit if parent has already failed
|
|
if (isDefined(parent.$$failure)) {
|
|
fail(parent.$$failure);
|
|
return result;
|
|
}
|
|
|
|
// Merge parent values if the parent has already resolved, or merge
|
|
// parent promises and wait if the parent resolve is still in progress.
|
|
if (parent.$$values) {
|
|
merged = merge(values, parent.$$values);
|
|
done();
|
|
} else {
|
|
extend(promises, parent.$$promises);
|
|
parent.then(done, fail);
|
|
}
|
|
|
|
// Process each invocable in the plan, but ignore any where a local of the same name exists.
|
|
for (var i=0, ii=plan.length; i<ii; i+=3) {
|
|
if (locals.hasOwnProperty(plan[i])) done();
|
|
else invoke(plan[i], plan[i+1], plan[i+2]);
|
|
}
|
|
|
|
function invoke(key, invocable, params) {
|
|
// Create a deferred for this invocation. Failures will propagate to the resolution as well.
|
|
var invocation = $q.defer(), waitParams = 0;
|
|
function onfailure(reason) {
|
|
invocation.reject(reason);
|
|
fail(reason);
|
|
}
|
|
// Wait for any parameter that we have a promise for (either from parent or from this
|
|
// resolve; in that case study() will have made sure it's ordered before us in the plan).
|
|
forEach(params, function (dep) {
|
|
if (promises.hasOwnProperty(dep) && !locals.hasOwnProperty(dep)) {
|
|
waitParams++;
|
|
promises[dep].then(function (result) {
|
|
values[dep] = result;
|
|
if (!(--waitParams)) proceed();
|
|
}, onfailure);
|
|
}
|
|
});
|
|
if (!waitParams) proceed();
|
|
function proceed() {
|
|
if (isDefined(result.$$failure)) return;
|
|
try {
|
|
invocation.resolve($injector.invoke(invocable, self, values));
|
|
invocation.promise.then(function (result) {
|
|
values[key] = result;
|
|
done();
|
|
}, onfailure);
|
|
} catch (e) {
|
|
onfailure(e);
|
|
}
|
|
}
|
|
// Publish promise synchronously; invocations further down in the plan may depend on it.
|
|
promises[key] = invocation.promise;
|
|
}
|
|
|
|
return result;
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Resolves a set of invocables. An invocable is a function to be invoked via `$injector.invoke()`,
|
|
* and can have an arbitrary number of dependencies. An invocable can either return a value directly,
|
|
* or a `$q` promise. If a promise is returned it will be resolved and the resulting value will be
|
|
* used instead. Dependencies of invocables are resolved (in this order of precedence)
|
|
*
|
|
* - from the specified `locals`
|
|
* - from another invocable that is part of this `$resolve` call
|
|
* - from an invocable that is inherited from a `parent` call to `$resolve` (or recursively
|
|
* from any ancestor `$resolve` of that parent).
|
|
*
|
|
* The return value of `$resolve` is a promise for an object that contains (in this order of precedence)
|
|
*
|
|
* - any `locals` (if specified)
|
|
* - the resolved return values of all injectables
|
|
* - any values inherited from a `parent` call to `$resolve` (if specified)
|
|
*
|
|
* The promise will resolve after the `parent` promise (if any) and all promises returned by injectables
|
|
* have been resolved. If any invocable (or `$injector.invoke`) throws an exception, or if a promise
|
|
* returned by an invocable is rejected, the `$resolve` promise is immediately rejected with the same error.
|
|
* A rejection of a `parent` promise (if specified) will likewise be propagated immediately. Once the
|
|
* `$resolve` promise has been rejected, no further invocables will be called.
|
|
*
|
|
* Cyclic dependencies between invocables are not permitted and will caues `$resolve` to throw an
|
|
* error. As a special case, an injectable can depend on a parameter with the same name as the injectable,
|
|
* which will be fulfilled from the `parent` injectable of the same name. This allows inherited values
|
|
* to be decorated. Note that in this case any other injectable in the same `$resolve` with the same
|
|
* dependency would see the decorated value, not the inherited value.
|
|
*
|
|
* Note that missing dependencies -- unlike cyclic dependencies -- will cause an (asynchronous) rejection
|
|
* of the `$resolve` promise rather than a (synchronous) exception.
|
|
*
|
|
* Invocables are invoked eagerly as soon as all dependencies are available. This is true even for
|
|
* dependencies inherited from a `parent` call to `$resolve`.
|
|
*
|
|
* As a special case, an invocable can be a string, in which case it is taken to be a service name
|
|
* to be passed to `$injector.get()`. This is supported primarily for backwards-compatibility with the
|
|
* `resolve` property of `$routeProvider` routes.
|
|
*
|
|
* @function
|
|
* @param {Object.<string, Function|string>} invocables functions to invoke or `$injector` services to fetch.
|
|
* @param {Object.<string, *>} [locals] values to make available to the injectables
|
|
* @param {Promise.<Object>} [parent] a promise returned by another call to `$resolve`.
|
|
* @param {Object} [self] the `this` for the invoked methods
|
|
* @return {Promise.<Object>} Promise for an object that contains the resolved return value
|
|
* of all invocables, as well as any inherited and local values.
|
|
*/
|
|
this.resolve = function (invocables, locals, parent, self) {
|
|
return this.study(invocables)(locals, parent, self);
|
|
};
|
|
}
|
|
|
|
angular.module('ui.router.util').service('$resolve', $Resolve);
|
|
|
|
</code></pre>
|
|
</article>
|
|
</section>
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
<nav>
|
|
<h2><a href="index.html">Index</a></h2><h3>Modules</h3><ul><li><a href="$resolve.html">$resolve</a></li></ul><h3>Classes</h3><ul><li><a href="$templateFactory.html">$templateFactory</a></li><li><a href="$urlMatcherFactory.html">$urlMatcherFactory</a></li><li><a href="UrlMatcher.html">UrlMatcher</a></li></ul><h3>Global</h3><ul><li><a href="global.html#ancestors">ancestors</a></li><li><a href="global.html#arraySearch">arraySearch</a></li><li><a href="global.html#equalForKeys">equalForKeys</a></li><li><a href="global.html#filterByKeys">filterByKeys</a></li><li><a href="global.html#inheritParams">inheritParams</a></li><li><a href="global.html#keys">keys</a></li><li><a href="global.html#normalize">normalize</a></li></ul>
|
|
</nav>
|
|
|
|
<br clear="both">
|
|
|
|
<footer>
|
|
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.2.2</a> on Mon Dec 09 2013 13:59:32 GMT-0500 (EST)
|
|
</footer>
|
|
|
|
<script> prettyPrint(); </script>
|
|
<script src="scripts/linenumber.js"> </script>
|
|
</body>
|
|
</html>
|