2

我正在制作一个相当复杂的 HTML 5 + Javascript 游戏。客户端将不得不根据他们所在的区域在游戏的不同点下载图像和数据。我在解决 Javascript 架构的数据层部分的一些问题时遇到了很大的问题。

我需要用数据层解决的问题:

  1. 每当调用服务器以检索新数据时,应用程序中使用的过时数据都需要自动更新。
  2. 从服务器检索的数据应存储在本地,以减少因两次请求相同数据而产生的任何开销。
  3. 无论数据是否已经在本地可用,任何需要访问数据的代码部分都应该能够以统一的方式轻松地检索它。

我试图做的是构建一个数据层,它有两个主要组成部分: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);
}

这有几个问题一直困扰着我。我会按照最烦人的顺序列出它们:)。

  1. 每当我必须添加一个经过此过程的呼叫时,都需要花费太多时间。(至少一个小时)
  2. 跳转和回调传递的数量变得令人困惑,并且似乎很容易出错。
  3. 我存储数据的分层方式非常难以同步和管理。更多关于下一个。

关于上面的问题 #3,如果我在数据层中存储的对象具有如下结构:

this.Account = {Battles[{ Teams: [{ TeamId: 392, Characters: [{}] }] }]}
this.Teams[392] = {Characters: [{}]}

因为我想以一种可以传递 TeamId 来检索数据的方式存储团队(例如return Teams[392];),但我也想存储与他们所在的战斗相关的团队(this.Account.Battles[0].Teams[0]);我有一个噩梦,让同一个团队的每个实例保持新鲜并保持相同的对象身份(所以我实际上并没有将它存储两次,这样我的数据就会在任何使用它的地方自动更新,这是目标#1数据层)。

它只是看起来如此凌乱和混乱。

我真的很感激任何帮助。

谢谢

4

2 回答 2

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
}

而且您可能不太容易出错。您甚至可以嵌套延迟对象,或将它们组合起来,以便在下载多个服务器调用之前不会调用回调。

于 2012-04-28T06:31:14.520 回答
1

骨干+1——它为你做了一些很重的工作。

还可以查看 Douglas Crockford 的 Javascript the Good Parts 一书中的 Memoizer。它很浓,但很棒。我修改了它以使memo数据存储成为可选,并添加了更多功能,例如无需先查询即可设置值的能力——例如处理数据新鲜度。

于 2012-05-04T05:41:22.783 回答