Permalink
Browse files

Merge branch 'develop-perf' of git://github.com/yahoo/mojito into par…

…tials
  • Loading branch information...
2 parents 5948e36 + a691fcc commit e6499c55ef3a848244cfc4b90b0d350347810450 @caridy committed Nov 20, 2012
@@ -222,6 +222,9 @@ YUI.add('ReadController-tests', function(Y) {
return {
config: {
+ getAppConfig: function() {
+ return {spaceid: '999', limit: 10};
+ },
getDefinition: function(ignored) {
return _definitions;
}
@@ -235,10 +238,12 @@ YUI.add('ReadController-tests', function(Y) {
}
},
models: {
- rss: {
- get: function(feedmeta, cb) {
- cb(null, feedmeta, boomtown_vudata_out);
- }
+ get: function() {
+ return {
+ get: function(feedmeta, cb) {
+ cb(null, feedmeta, boomtown_vudata_out);
+ }
+ };
}
}
};
@@ -295,21 +300,29 @@ YUI.add('ReadController-tests', function(Y) {
},
'compose spaceid set': function() {
+ controller.config = controller.config || {};
+ controller.config.spaceid = '999';
A.areSame('999', controller.compose(boomtown_feedmeta, boomtown_stories_in).spaceid);
},
'compose feedname': function() {
+ controller.config = controller.config || {};
+ controller.config.spaceid = '999';
A.areSame('BoomTown', controller.compose(boomtown_feedmeta, boomtown_stories_in).feedname);
},
'compose navdots for every story': function() {
+ controller.config = controller.config || {};
+ controller.config.spaceid = '999';
var vu = controller.compose(boomtown_feedmeta, boomtown_stories_in);
A.areSame(10, vu.navdots.length);
A.areSame(vu.stories.length, vu.navdots.length);
},
'compose adds css': function() {
+ controller.config = controller.config || {};
+ controller.config.spaceid = '999';
var vu = controller.compose(boomtown_feedmeta, boomtown_stories_in);
Y.each(vu.stories, function(story, i) {
A.isTypeOf('string', story.css_style);
@@ -152,7 +152,7 @@ YUI.add('ReadModelRss-tests', function(Y, NAME) {
suite.add(new YUITest.TestCase({
name: 'rss model tests',
setUp: function() {
- rss = Y.mojito.models.rss;
+ rss = Y.mojito.models.ReadModelRss;
rss.init({limit: 10});
},
@@ -18,6 +18,12 @@ YUI.add('mojito-dispatcher', function (Y, NAME) {
'use strict';
+ // on the server side, controllers are stateless, but on
+ // the client, things are different, we can cache them by
+ // instanceId to re-use them when possible.
+ var _cacheInstances = {},
+ _cacheControllers = {};
+
Y.namespace('mojito').Dispatcher = {
/**
@@ -60,17 +66,11 @@ YUI.add('mojito-dispatcher', function (Y, NAME) {
instance = command.instance,
modules = [];
- // For performance reasons we don't want to support
- // this ondemand "use" in the server side since
- // all the requirements are already in place.
- if (command.context.runtime === 'server') {
- adapter.error(new Error('Invalid controller name [' +
- instance.controller + '] for mojit [' +
- instance.type + '].'));
- return;
- }
+ // TODO: part of the optimization here can be to
+ // avoid calling use when the controller already exists.
- // attach controller to Y ondemand
+ // use controller's yui module name to attach
+ // the controller to Y ondemand
modules.push(instance.controller);
// TODO: this is a hack to attach the correct engine, the problem
@@ -105,23 +105,32 @@ YUI.add('mojito-dispatcher', function (Y, NAME) {
*/
_createActionContext: function (command, adapter) {
var ac,
- controller = Y.mojito.controllers[command.instance.controller],
perf = Y.mojito.perf.timeline('mojito', 'ac:ctor',
'create ControllerContext', command);
+ // the controller is not stateless on the client, we
+ // store it for re-use.
+ // TODO: we need to find a way to clean this for apps
+ // that attent to create and destroy mojits from the page
+ // but maybe we can just wait for the YAF refactor.
+ if (!_cacheControllers[command.instance.instanceId]) {
+ _cacheControllers[command.instance.instanceId] =
+ Y.mojito.util.heir(Y.mojito.controllers[command.instance.controller]);
+ }
+
// Note that creation of an ActionContext current causes
// immediate invocation of the dispatch() call.
try {
ac = new Y.mojito.ActionContext({
command: command,
- controller: Y.mojito.util.heir(controller),
+ controller: _cacheControllers[command.instance.instanceId],
dispatcher: this, // NOTE passing dispatcher.
adapter: adapter,
store: this.store
});
} catch (e) {
Y.log('Error from dispatch on instance \'' +
- (command.instance.id || '@' + command.instance.type) +
+ (command.instance.base || '@' + command.instance.type) +
'\':', 'error', NAME);
Y.log(e.message, 'error', NAME);
Y.log(e.stack, 'error', NAME);
@@ -146,8 +155,8 @@ YUI.add('mojito-dispatcher', function (Y, NAME) {
} else {
- adapter.error(new Error('RPC tunnel is not available in the ' +
- command.context.runtime + ' runtime.'));
+ adapter.error(new Error('RPC tunnel is not available in the [' +
+ command.context.runtime + '] runtime.'));
}
},
@@ -171,11 +180,22 @@ YUI.add('mojito-dispatcher', function (Y, NAME) {
store.validateContext(command.context);
if (command.rpc) {
- // forcing to dispatch command through RPC tunnel
+ Y.log('Command with rpc flag, dispatching through RPC tunnel',
+ 'info', NAME);
this.rpc(command, adapter);
return;
}
+ if (command.instance.instanceId && _cacheInstances[command.instance.instanceId]) {
+ Y.log('Re-using instance with instanceId=' +
+ command.instance.instanceId, 'info', NAME);
+ command.instance = _cacheInstances[command.instance.instanceId];
+ this._useController(command, adapter);
+ return;
+ }
+
+ // if no rpc flag and no instance cached, we try to
+ // expand the instance before creating the ActionContext.
store.expandInstance(command.instance, command.context,
function (err, instance) {
@@ -199,19 +219,19 @@ YUI.add('mojito-dispatcher', function (Y, NAME) {
}
+ // the instance is not stateless on the client, we
+ // store it for re-use.
+ // TODO: we need to find a way to clean this for apps
+ // that attent to create and destroy mojits from the page
+ // but maybe we can just wait for the YAF refactor.
+ _cacheInstances[instance.instanceId] = instance;
+
// We replace the given instance with the expanded instance.
command.instance = instance;
- // if this controller does not exist yet, we should try
- // to require it along with it depedencies.
- if (!Y.mojito.controllers[instance.controller]) {
- // requiring the controller and its dependencies
- // before dispatching AC
- my._useController(command, adapter);
- } else {
- // dispatching AC
- my._createActionContext(command, adapter);
- }
+ // requiring the controller and its dependencies
+ // before dispatching AC
+ my._useController(command, adapter);
});
}
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2011-2012, Yahoo! Inc. All rights reserved.
+ * Copyrights licensed under the New BSD License.
+ * See the accompanying LICENSE file for terms.
+ */
+
+/*jslint anon:true, nomen:true*/
+/*global YUI*/
+
+
+/**
+ * This object is responsible for running mojits.
+ * @class MojitoDispatcher
+ * @static
+ * @public
+ */
+YUI.add('mojito-dispatcher', function (Y, NAME) {
+
+ 'use strict';
+
+ Y.namespace('mojito').Dispatcher = {
+
+ /**
+ * Initializes the dispatcher instance.
+ * @method init
+ * @public
+ * @param {Y.mojito.ResourceStore} resourceStore the store to use.
+ * @param {Y.mojito.TunnelClient} rpcTunnel optional tunnel client for RPC calls
+ * @return {Y.mojito.Dispatcher}
+ */
+ init: function (resourceStore, rpcTunnel) {
+
+ if (!resourceStore) {
+ throw new Error(
+ 'Mojito cannot instantiate without a resource store.'
+ );
+ }
+
+ // Cache parameters as instance variables for the dispatch() call to
+ // reference.
+ this.store = resourceStore;
+ this.tunnel = rpcTunnel;
+
+ Y.log('Dispatcher created', 'debug', NAME);
+
+ return this;
+ },
+
+ /**
+ * Create AC object for a particular controller.
+ * @method _createActionContext
+ * @protected
+ * @param {object} command the command to dispatch
+ * @param {OutputAdapter} adapter the output adapter
+ */
+ _createActionContext: function (command, adapter) {
+ var ac,
+ controller = Y.mojito.controllers[command.instance.controller],
+ perf = Y.mojito.perf.timeline('mojito', 'ac:ctor',
+ 'create ControllerContext', command);
+
+ // Note that creation of an ActionContext current causes
+ // immediate invocation of the dispatch() call.
+ try {
+ ac = new Y.mojito.ActionContext({
+ command: command,
+ controller: Y.mojito.util.heir(controller),
+ dispatcher: this, // NOTE passing dispatcher.
+ adapter: adapter,
+ store: this.store
+ });
+ } catch (e) {
+ Y.log('Error from dispatch on instance \'' +
+ (command.instance.id || '@' + command.instance.type) +
+ '\':', 'error', NAME);
+ Y.log(e.message, 'error', NAME);
+ Y.log(e.stack, 'error', NAME);
+ adapter.error(e);
+ }
+ perf.done(); // closing the 'ac:ctor' timeline
+ },
+
+ /**
+ * Executes a command in a remote runtime if possible.
+ * @method rpc
+ * @public
+ * @param {object} command the command to dispatch
+ * @param {OutputAdapter} adapter the output adapter
+ */
+ rpc: function (command, adapter) {
+ if (this.tunnel) {
+
+ Y.log('Dispatching instance "' + (command.instance.base || '@' +
+ command.instance.type) + '" through RPC tunnel.', 'info', NAME);
+ this.tunnel.rpc(command, adapter);
+
+ } else {
+
+ adapter.error(new Error('RPC tunnel is not available in the ' +
+ command.context.runtime + ' runtime.'));
+
+ }
+ },
+
+ /**
+ * Dispatch a command in the current runtime, or fallback
+ * to a remote runtime when posible.
+ * @method dispatch
+ * @public
+ * @param {object} command the command to dispatch
+ * @param {OutputAdapter} adapter the output adapter
+ */
+ dispatch: function (command, adapter) {
+
+ var my = this,
+ store = this.store,
+ perf = Y.mojito.perf.timeline('mojito',
+ 'dispatch:expandInstance',
+ 'gather details about mojit', command);
+
+ store.validateContext(command.context);
+
+ if (command.rpc) {
+ // forcing to dispatch command through RPC tunnel
+ this.rpc(command, adapter);
+ return;
+ }
+
+ store.expandInstance(command.instance, command.context,
+ function (err, instance) {
+
+ perf.done(); // closing 'dispatch:expandInstance' timeline
+
+ if (err || !instance || !instance.controller) {
+
+ adapter.error(new Error('Cannot expand instance [' + (command.instance.base || '@' +
+ command.instance.type) + '], or instance.controller is undefined'));
+ return;
+
+ }
+
+ // We replace the given instance with the expanded instance.
+ command.instance = instance;
+
+ if (!Y.mojito.controllers[instance.controller]) {
+ // the controller was not found, we should halt
+ adapter.error(new Error('Invalid controller name [' +
+ command.instance.controller + '] for mojit [' +
+ command.instance.type + '].'));
+ } else {
+ // dispatching AC
+ my._createActionContext(command, adapter);
+ }
+
+ });
+ }
+
+ };
+
+}, '0.1.0', {requires: [
+ 'mojito-action-context',
+ 'mojito-util'
+]});
@@ -118,7 +118,7 @@ module.exports = function(dir, excludes) {
return modules;
}
- if (Y.Lang.isArray(dir)) {
+ if (!Y.Lang.isArray(dir)) {
dir = [dir];
}
Oops, something went wrong.

0 comments on commit e6499c5

Please sign in to comment.