私はかなり複雑なHTML5+Javascriptゲームを作っています。クライアントは、彼らがいるエリアに応じて、ゲームのさまざまなポイントで画像とデータをダウンロードする必要があります。Javascriptアーキテクチャのデータレイヤー部分に関するいくつかの問題を解決するのに大きな問題があります。
データレイヤーで解決する必要のある問題:
- 古くなったアプリケーションで使用されているデータは、新しいデータを取得するサーバーが呼び出されるたびに自動的に更新される必要があります。
- サーバーから取得したデータは、同じデータを2回要求することによるオーバーヘッドを減らすために、ローカルに保存する必要があります。
- データへのアクセスが必要なコードのどの部分でも、データがすでにローカルで利用可能かどうかに関係なく、簡単かつ均一な方法でデータを取得できる必要があります。
これを達成するために私が試みたのは、2つの主要なコンポーネントを持つデータレイヤーを構築することです。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時間)
- ジャンプとコールバックの受け渡しの量は混乱を招き、エラーが発生しやすいようです。
- データを格納する階層的な方法は、同期と管理が非常に困難です。その次の詳細。
上記の問題#3に関して、次のような構造を持つ保存されているオブジェクトがデータレイヤーにある場合:
this.Account = {Battles[{ Teams: [{ TeamId: 392, Characters: [{}] }] }]}
this.Teams[392] = {Characters: [{}]}
TeamIdを渡してデータを取得できる方法でチームを保存したいので(例return Teams[392];
)、チームが存在するバトルに関連してチームも保存したいので(this.Account.Battles[0].Teams[0]
); 同じチームの各インスタンスを最新の状態に保ち、同じオブジェクトIDを維持するという悪夢があります(したがって、実際には2回保存するのではなく、使用されている場所でデータが自動的に更新されるようにします。これは、データレイヤー)。
それはとても厄介でごちゃごちゃしているようです。
助けてくれて本当に感謝しています。
ありがとう