de
Version:
Simple asynchronous promise-based controller
202 lines (149 loc) • 3.86 kB
JavaScript
'use strict';
var JSPromise;
var hasProperty;
JSPromise = /** @type JSPromise */ require('jspromise');
hasProperty = Object.prototype.hasOwnProperty;
/**
* @class Runtime
*
* @param {Provider} agent
* @param {Object} [params]
* */
function Runtime (agent, params) {
var i;
/**
* @public
* @memberOf {Runtime}
* @property {Provider}
* */
this.agent = agent;
/**
* @public
* @memberOf {Runtime}
* @property {Object}
* */
this.params = {};
/**
* @public
* @memberOf {Runtime}
* @property {Object}
* */
for ( i in params ) {
if ( hasProperty.call(params, i) ) {
this.params[i] = params[i];
}
}
/**
* @public
* @memberOf {Runtime}
* @property {Object}
* */
this.promised = {};
}
Runtime.prototype = {
/**
* @protected
* @memberOf {Runtime}
* @method
* */
constructor: Runtime,
/**
* @public
* @memberOf {Runtime}
* @method
*
* @param {String} goal
*
* @returns {JSPromise}
* */
invoke: function (goal) {
var agent;
var decl;
var promise;
var runtime;
var start;
// already invoked in current runtime
if ( hasProperty.call(this.promised, goal) ) {
return this.promised[goal];
}
agent = this.agent;
promise = agent.cache.get(goal);
// agent cache
if ( promise instanceof JSPromise ) {
this.promised[goal] = promise;
return promise;
}
decl = agent.decl(goal);
runtime = this;
start = Date.now();
promise = this.resolve(decl.deps).then(function (value) {
var data;
data = decl.data;
if ( 'function' === typeof data ) {
return data.apply(runtime, value.toArguments());
}
return data;
});
this.promised[goal] = promise;
// set agent cache
agent.cache.set(goal, promise, decl);
promise.always(function (promise) {
agent.emit(['accept', 'reject'][ +promise.isRejected() ], {
path: goal,
time: Date.now() - start,
data: promise.valueOf()
});
}).done();
return promise;
},
/**
* @public
* @memberOf {Runtime}
* @method
*
* @param {String|Array<String>} goals
*
* @returns {JSPromise}
* */
resolve: function (goals) {
var agent;
var i;
var l;
var promises;
agent = this.agent;
if ( !Array.isArray(goals) ) {
if ( null === goals || void 0 === goals ) {
goals = [];
} else {
goals = [goals];
}
}
promises = {};
for ( i = 0, l = goals.length; i < l; i += 1 ) {
promises[goals[i]] = this.invoke(goals[i]);
}
return JSPromise.allResolved(promises).then(function (promises) {
var bundle;
var data;
var goal;
var promise;
bundle = agent.createBundle();
for ( goal in promises ) {
/*jshint forin: false*/
if ( !hasProperty.call(promises, goal) ) {
continue;
}
promise = promises[goal];
data = promise.valueOf();
goal = agent.getPath(goal);
if ( promise.isRejected() ) {
bundle.setError(goal, data);
continue;
}
bundle.setResult(goal, data);
}
return bundle;
});
}
};
module.exports = Runtime;