关于这个简单框架设计的有效性,也许你认为这很糟糕,但我真的只是想让它工作并且学习某些设计好坏的难点。我想让它工作,即使它是一个糟糕的设计。
所以我面临着一个挑战:如果根据另一个服务定义服务的代码在之前执行它依赖的服务,它会认为该组件不存在。因为该代码尚未执行。我的目标是能够以任何顺序执行定义服务的代码。
希望这有点道理。这个问题对我来说有点难以解释,但我的目标是编写如下代码:
new Service('machine', ['machine / components / gear'], function(gear) {
alert('This machine depends on a ' + gear);
}).initialize();
new Service('machine / components / gear', ['machine / components / gear / components / cog'], function(cog) {
return 'gear wich depends on a ' + cog;
});
new Service('machine / components / gear / components / cog', [], function(cog) {
return 'cog';
});
为了这个问题,提供给Service构造函数的第一个参数是服务的名称。我最初编写框架的方式,在这种情况下'machine'
在'machine / components / gear'
之前执行,因此它看不到'machine / components / gear'
存在,同样地,'machine / components / gear'
之前执行'machine / components / gear / components / cog'
因此无法使用该组件。
注意,在显示代码之前:你会看到框架中使用的count
变量,以及一些奇怪的东西,基本上它都非常简单和整洁,直到我开始尝试缓解这个问题我是有。正如您将看到的那样,我试图解决问题,当找不到依赖项时,使用setTimeout
并再次尝试,直到count
增加几次,因此事件循环已完成几次,也许其他服务已完成执行。这很麻烦,可能是一种可怕的方式。
以下是代码:
var Directory = function() {
this.directories = {};
this.items = {};
};
var root = new Directory();
var Service = function(name, dependencies, func, count) {
if (!count) {
count = 0;
}
var that = this;
this.name = name;
this.wait = false;
this.dependencyCollection = [];
this.func = func;
this.initialize = function() {
setTimeout(function() {
console.log('Initializing with dependency collection: '); //debugging
console.log(that.dependencyCollection); //debugging
that.func.apply(null, that.dependencyCollection);
}, 10);
};
this.eventHandlers = {};
this.trigger = function(name) {
if (that.eventHandlers[name]) {
that.eventHandlers[name]();
}
};
this.on = function(name, func) {
that.eventHandlers[name] = func;
};
this.mutate = function(dependencies, func) {
new Service(that.name, dependencies, func);
that.trigger('mutate');
};
for (var x = 0; x < dependencies.length; x++) {
var nameSegments = dependencies[x].split(' / ');
var service = root;
var servicePlaceholder = service;
for (var i = 0; i < nameSegments.length; i++) {
var segment = nameSegments[i];
if (i === nameSegments.length - 1) {
if (servicePlaceholder.items[segment]) {
console.log('Observing dependency: ' + servicePlaceholder.items[segment]());
this.dependencyCollection.push(servicePlaceholder.items[segment]());
} else {
if (count < 3) {
(function(count) {
setTimeout(function() {
count++;
new Service(name, dependencies, func, count);
}, 1)
})(count);
} else {
throw 'Dependent item missing: ' + JSON.stringify(servicePlaceholder.items, null, 3) + ' (' + dependencies + ": " + segment + ')';
}
}
} else if (servicePlaceholder.directories[segment]) {
servicePlaceholder = servicePlaceholder.directories[segment];
} else {
if (count < 3) {
(function(count) {
setTimeout(function() {
count++;
new Service(name, dependencies, func, count);
}, 1)
})(count);
} else {
throw 'Dependent directory missing: ' + JSON.stringify(servicePlaceholder.directories, null, 3) + ' (' + segment + ')';
}
}
}
}
var directory = root;
var directoryPlaceholder = directory;
var nameSegments = name.split(' / ');
for (var i = 0; i < nameSegments.length; i++) {
var segment = nameSegments[i];
if (i === nameSegments.length - 1) {
console.log('Observing dependency collection: ' + that.dependencyCollection);
directoryPlaceholder.items[segment] = function() {
return that.func.apply(null, that.dependencyCollection);
}
} else {
if (directoryPlaceholder.directories[segment]) {
directoryPlaceholder = directoryPlaceholder.directories[segment];
} else {
directoryPlaceholder.directories[segment] = new Directory();
directoryPlaceholder = directoryPlaceholder.directories[segment];
}
}
}
};
如果那里的任何内容没有意义,那就假设这是一个徒劳的尝试来缓解这个问题。我已经和它一起工作了好几个小时,最后决定我无处可去并寻求帮助。如果有人可以帮我弄清楚如何使这个(也许是可怕的)模型正确执行,我真的很感激。
没有超时和计数器以及诸如此类的代码的示例,只有在按时间顺序定义组件时才能正常工作:
var Directory = function() {
this.directories = {};
this.items = {};
};
var root = new Directory();
var Service = function(name, dependencies, func) {
var that = this;
this.name = name;
this.wait = false;
this.dependencyCollection = [];
this.func = func;
this.initialize = function() {
that.func.apply(null, that.dependencyCollection);
};
this.eventHandlers = {};
this.trigger = function(name) {
if (that.eventHandlers[name]) {
that.eventHandlers[name]();
}
};
this.on = function(name, func) {
that.eventHandlers[name] = func;
};
this.mutate = function(dependencies, func) {
new Service(that.name, dependencies, func);
that.trigger('mutate');
};
for (var x = 0; x < dependencies.length; x++) {
var nameSegments = dependencies[x].split(' / ');
var service = root;
var servicePlaceholder = service;
for (var i = 0; i < nameSegments.length; i++) {
var segment = nameSegments[i];
if (i === nameSegments.length - 1) {
if (servicePlaceholder.items[segment]) {
console.log('Observing dependency: ' + servicePlaceholder.items[segment]());
this.dependencyCollection.push(servicePlaceholder.items[segment]());
} else {
throw 'Dependent item missing: ' + JSON.stringify(servicePlaceholder.items, null, 3) + ' (' + dependencies + ": " + segment + ')';
}
} else if (servicePlaceholder.directories[segment]) {
servicePlaceholder = servicePlaceholder.directories[segment];
} else {
throw 'Dependent directory missing: ' + JSON.stringify(servicePlaceholder.directories, null, 3) + ' (' + segment + ')';
}
}
}
var directory = root;
var directoryPlaceholder = directory;
var nameSegments = name.split(' / ');
for (var i = 0; i < nameSegments.length; i++) {
var segment = nameSegments[i];
if (i === nameSegments.length - 1) {
console.log('Observing dependency collection: ' + that.dependencyCollection);
directoryPlaceholder.items[segment] = function() {
return that.func.apply(null, that.dependencyCollection);
}
} else {
if (directoryPlaceholder.directories[segment]) {
directoryPlaceholder = directoryPlaceholder.directories[segment];
} else {
directoryPlaceholder.directories[segment] = new Directory();
directoryPlaceholder = directoryPlaceholder.directories[segment];
}
}
}
};
setTimeout(function() {
console.log(root);
}, 1000);
new Service('machine / components / gear / components / cog', [], function(cog) {
return 'cog';
});
new Service('machine / components / gear', ['machine / components / gear / components / cog'], function(cog) {
return 'gear wich depends on a ' + cog;
});
new Service('machine', ['machine / components / gear'], function(gear) {
alert('This machine depends on a ' + gear);
}).initialize();
答案 0 :(得分:1)
处理此问题的一种方法是将缺少依赖项的服务添加到队列中。每次注册新组件时,查看队列中的项是否具有所需的依赖项。
最后,为了捕获依赖未解析的情况,使用setTimeout
在所有脚本加载后检查队列,并报告任何从未有过依赖关系的组件解决。
var Service = (function() {
var _registered = {};
var _waiting = [];
// Check if all dependencies have been resolved
setTimeout(function() {
_waiting.forEach(function(obj) {
throw new Error('Failed to resolve dependencies for ' + obj.name);
});
}, 1);
function allDependenciesLoaded(dependencies) {
return dependencies.every(function(dep) {
return !!_registered[dep];
});
}
function processWaiting() {
for (var i = _waiting.length - 1; i >= 0; i--) {
var obj = _waiting[i];
if (allDependenciesLoaded(obj.dependencies)) {
_waiting.splice(i, 1);
obj.func();
}
}
}
return function(componentName, dependencies, func) {
_registered[componentName] = func;
if (!allDependenciesLoaded(dependencies)) {
_waiting.push({
name: componentName,
dependencies: dependencies,
func: func
});
} else {
func();
}
processWaiting();
};
})();
new Service('D', ['this', 'one', 'will', 'fail'], function() {});
new Service('A', ['B', 'C'], function() {
console.log('A is ready');
});
new Service('B', [], function() {
console.log('B is ready');
});
new Service('C', [], function() {
console.log('C is ready');
});
&#13;