我正在制作一个相当复杂的HTML 5 + Javascript游戏。客户端将不得不根据他们所在的区域在游戏的不同位置下载图像和数据。我在解决Javascript架构的数据层部分的一些问题时遇到了很大的问题。
我需要使用数据层解决的问题:
我为实现这一目标而尝试做的是构建一个包含两个主要组件的数据层: 1.层的一部分,用于访问数据(通过get *方法) 2.层的一部分,用于存储本地数据并将其与服务器中的数据同步。
工作流程如下:
当游戏需要访问某些数据时,它会在数据层中为该数据调用get *方法,并传递回调函数。
bs.data.getInventory({ teamId: this.refTeam.PartyId, callback: this.inventories.initialize.bind(this.inventories) });
get *方法确定数据是否已在本地可用。如果是这样,它或者直接返回数据(如果没有指定回调)或者调用回调函数将数据传递给它。
如果数据不可用,它会在本地存储回调方法(setupListener)并调用通信对象传递最初请求的信息。
getInventory: function (obj) {
if ((obj.teamId && !this.teamInventory[obj.teamId]) || obj.refresh) {
this.setupListener(this.inventoryNotifier, obj);
bs.com.getInventory({ teamId: obj.teamId });
}
else if (typeof (obj.callback) === "function") {
if (obj.teamId) {
obj.callback(this.team[obj.teamId].InventoryList);
}
}
else {
if (obj.teamId) {
return this.team[obj.teamId].InventoryList;
}
}
}
然后,通信对象对服务器进行ajax调用,并等待数据返回。
当返回数据时,再次调用数据层,要求它发布检索到的数据。
getInventory: function (obj) {
if (obj.teamId) {
this.doAjaxCall({ orig: obj, url: "/Item/GetTeamEquipment/" + obj.teamId, event: "inventoryRefreshed" });
}
},
doAjaxCall: function (obj) {
var that = this;
if (!this.inprocess[obj.url + obj.data]) {
this.inprocess[obj.url + obj.data] = true;
$.ajax({
type: obj.type || "GET",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: obj.data,
url: obj.url,
async: true,
success: function (data) {
try {
ig.fire(bs.com, obj.event, { data: data, orig: obj.orig });
}
catch (ex) {
// this enables ajaxComplete to fire
ig.log(ex.message + '\n' + ex.stack);
}
finally {
that.inprocess[obj.url + obj.data] = false;
}
},
error: function () { that.inprocess[obj.url + obj.data] = false; }
});
}
}
数据层然后将所有数据存储在本地对象中,最后调用原始回调函数,并将请求的数据传递给它。
publishInventory: function (data) {
if (!this.inventory) this.inventory = {};
for (var i = 0; i < data.data.length; i++) {
if (this.inventory[data.data[i].Id]) {
this.preservingUpdate(this.inventory[data.data[i].Id], data.data[i]);
}
else {
this.inventory[data.data[i].Id] = data.data[i];
}
}
// if we pulled this inventory for a team, update the team
// with the inventory
if (data.orig.teamId && this.team[data.orig.teamId]) {
this.teamInventory[data.orig.teamId] = true;
this.team[data.orig.teamId].InventoryList = [];
for (var i = 0; i < data.data.length; i++) {
this.team[data.orig.teamId].InventoryList.push(data.data[i]);
}
}
// set up the data we'll notify with
var notifyData = [];
for (var i = 0; i < data.data.length; i++) {
notifyData.push(this.inventory[data.data[i].Id]);
}
ig.fire(this.inventoryNotifier, "refresh", notifyData, null, true);
}
这有几个问题不断打扰我。我会按照最烦人的顺序列出它们:)。
关于上面的问题#3,如果数据层中的对象存储的结构看起来像这样:
this.Account = {Battles[{ Teams: [{ TeamId: 392, Characters: [{}] }] }]}
this.Teams[392] = {Characters: [{}]}
因为我希望以可以传递TeamId来检索数据的方式存储团队(例如return Teams[392];
),但我也希望将团队存储在与其存在的战斗相关的位置({{ 1}});我有一个时间的噩梦,保持同一团队的每个实例都保持新鲜并保持相同的对象标识(所以我实际上并没有将它存储两次,所以我的数据将自动更新,无论它在哪里使用,这是客观的#1数据层)。
它看起来非常混乱和混乱。
我真的很感激任何帮助。
由于
答案 0 :(得分:2)
您应该考虑使用jquery的延迟对象。
示例:
var deferredObject = $.Deferred();
$.ajax({
...
success: function(data){
deferredObject.resolve(data);
}
});
return deferredObject;
现在返回deferredObject,您可以像这样附加回调:
var inventoryDfd = getInventory();
$.when(inventoryDfd).done(function(){
// code that needs data to continue
}
你可能不太容易出错。您甚至可以嵌套延迟对象,或者将它们组合在一起,以便在下载多个服务器调用之前不会调用回调。
答案 1 :(得分:1)
+1 Backbone - 它为你做了一些非常繁重的工作。
另请参阅Douglas Crockford的书“Javascript the Good Parts”中的Memoizer。它很密集,但很棒。我将其破解以使memo
数据存储可选,并添加了更多内容,例如无需先查询即可设置值的功能 - 例如处理数据新鲜度。