【问题标题】:Javascript Data Layer Architecture AssistanceJavascript 数据层架构协助
【发布时间】:2012-04-28 05:59:35
【问题描述】:

我正在制作一个相当复杂的 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数据层)。

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

非常感谢任何帮助。

谢谢

【问题讨论】:

  • 您是否考虑过使用Backbone 或类似的客户端框架?这将为您解决很多繁重的工作。
  • 在实现此代码之前,我查看了主干。当时我觉得这不是我需要的。受够了我当前的代码,我今晚再次查看了骨干网,但我仍然觉得这不是我需要的。一方面,我不需要使用视图或模板(包括它们附带的任何数据绑定),另一方面,它似乎不需要处理任何本地索引存储,这正是我所追求的。跨度>
  • 你可以选择你需要的Backbone的部分,数据和事件管理部分即使你不使用视图也非常有用。我将把它留在这里:github.com/jeromegn/Backbone.localStorage
  • 很公平,我认为骨干网会简化路由。尽管我只知道我在教程中读到的内容可能并没有描绘出整个画面,但我认为它不能满足数据存储需求。
  • 再看一下数据存储问题,我认为如果有提供这种类型接口的 javascript 库,使用 nosql db 可能是合适的。我没有看到一个,但也许这会让别人的汁液流淌。

标签: javascript html data-layers


【解决方案1】:

您应该考虑使用 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
}

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

【讨论】:

  • 我为此查看了文档并阅读了两篇博客文章,但我不知道如何使用它来改善这种情况。您对我将在哪里使用它有什么建议吗?我可以使用它来代替为 ajax 调用提供成功函数,但它的工作原理基本相同。
【解决方案2】:

+1 for Backbone——它为你做了一些非常繁重的工作。

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

【讨论】:

  • 这是最接近我需要的东西。我也许可以使用memoizer。还没有时间完成我对它的任何研究,但赏金即将到期,所以我想将它奖励给最值得的答案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-06-06
  • 2010-11-29
  • 2015-06-17
  • 1970-01-01
  • 2011-11-27
  • 2012-11-30
  • 1970-01-01
相关资源
最近更新 更多