【问题标题】:Backbone js + Require js + backbone relational + circular dependency + self referencesBackbone js + Require js + 主干关系 + 循环依赖 + 自引用
【发布时间】:2014-02-06 03:59:12
【问题描述】:

我最近遇到了 Backbone 和 Require JS 的问题,因为我们有一个相当复杂的数据模型,我需要表示它导致循环依赖和自引用的问题。我已经在网上阅读了很多帖子(没有一个真正有效),但我想我已经找到了解决方案。因此,我想分享这一点,希望它可以帮助遇到这个问题的人,但也想问你们是否认为有办法收拾东西。

第一个问题是我有引用集合的模型,这些模型引用了引用集合的模型,所有这些都创建了一个很大的混乱循环依赖。坦率地说,这只是破坏了应用程序。这是一个伪代码示例:

Model A
  has Collection B

Collection B
  of Model B

Model B
  has Collection A
  has Collection C

Collection A
  of Model A

Collection C
  of Model C

Backbone docs 声明这可以通过以下方式实现:

  initialize: function() {
    this.messages = new Messages;
    this.messages.url = '/mailbox/' + this.id + '/messages';
    this.messages.on("reset", this.updateCounts);
  },

我尝试了各种方法来满足我们的需求,但我们复杂的嵌套需求打破了 Backbone。所以我偶然发现了backbone relational,并为我们的数据模型创建了一个基本的工作表示(这涉及创建一个 shim 以使用 Require JS)。从本质上讲,这奏效了。所以我扩展了这个例子,这样 Model C 也可以有 Collection C 的实例(自我引用)。这似乎再次奏效。优秀。但是,将示例应用于我的应用程序更加困难 - 将模型和集合拆分为单独的文件被证明更加困难,因为骨干关系期望集合和模型名称位于全局命名空间中(对于 Require 和“使用严格”有点棘手) .由于我们的数据模型复杂,我想使用字符串标识符来表示关系以进行前向引用,而不是显式的要求引用,这也被证明是困难的。我尝试将所有内容添加到导出命名空间,但这同样不起作用。无论如何,我认为通过将集合和模型添加到自定义命名空间,然后将此命名空间添加到骨干关系模型范围,我找到了解决方案。我已将我的自定义库命名为“Orca”(因为虎鲸实在是太棒了)。

bootstrap.js

require.config({
  paths: {
    "jquery"        : "../bower_components/jquery/jquery",
    "underscore"    : "../bower_components/underscore-amd/underscore",
    "backbone"      : "../bower_components/backbone-amd/backbone",
    "relational"    : "../bower_components/backbone-relational/backbone-relational",
    ...

  shim: {
    "underscore": {
      exports: "_"
    },
    "backbone": {
      deps: ["underscore", "jquery"],
      exports: "Backbone"
    },
    "relational": {
      deps: ["backbone"]
    },
    ...

app.js

define(["backbone", "relational", "libs/orca", "collections/a", "models/a", "collections/b", "models/b", "collections/c", "models/c"], function(Backbone, Relational, Orca){
  "use strict";

  var App = function(options) {
    this.initialize(otions);
  }; 

  App.prototype = _.extend(Backbone.Events, {

    initialize: function(options) {
      Orca.initialize();

      var a = new Orca.Relational.ModelA([],{});
    }
  }

  return App;
});

lib/orca.js

define(["backbone", "relational"], function(Backbone) {
  "use strict";

  var Orca = {
    Relational: {},

    initialize: function() {
      Backbone.Relational.store.addModelScope(this.Relational);      
    }
  };

  // I actually extend Backbone.RelationalModel so I can have custom methods,
  // e.g. "parse" but I've simplified the code for example's sake...
  Orca.Model = Backbone.RelationalModel;
  Orca.Collection = Backbone.Collection;

  return Orca;
});

collections/a.js

define(["backbone", "libs/orca"], function(Backbone, Orca) {
  "use strict";

  Orca.Relational.CollectionA = Backbone.Collection.extend({});
});

模型/a.js

define(["backbone", "libs/orca"], function(Backbone, Orca) {
  "use strict";

  Orca.Relational.ModelA = Orca.Model.extend({
    relations: [
      {
        type: Backbone.HasMany,
        key: "bs",
        relatedModel: "ModelB",
        includeInJSON: Backbone.Model.prototype.idAttribute,
        collectionType: "CollectionB",
        reverseRelation: {
          key: "a"
        }
      }
    ]
  });
});

CollectionB 和 ModelB 相似,因此为简洁起见,我省略了这些。

为了展示自我参照:

define(["backbone", "libs/orca"], function(Backbone, Orca) {
  "use strict";

  Orca.Relational.ModelC = Orca.Model.extend({
    relations: [
      {
        type: Backbone.HasMany,
        key: "cs",
        relatedModel: "ModelC",
        includeInJSON: Backbone.Model.prototype.idAttribute,
        collectionType: "CollectionC",
        reverseRelation: {
          key: "c"
        }
      }
    ]
  });
});

所以我对这段代码的错误是在 app.js 中我创建了一个新的 ModelA 实例。但是因为这引用了 CollectionB,而 ModelB 又使用了 ModelB,而 ModelB 又引用了 Collection C 并使用了 Model C,所以我必须将所有这些引用为必需的依赖项。有没有更好的方法来做到这一点?

【问题讨论】:

  • 也许将集合和模型添加到“窗口”对象可能会消除对自定义对象的需求,但我喜欢将事物排除在全局对象之外的想法

标签: javascript backbone.js circular-dependency backbone-relational self-reference


【解决方案1】:

我实际上已经停止使用 Backbone Relational,现在我正在使用 JJRelational,因为它允许多对多关系。通过创建一个名为“relational.js”的新文件,该文件引用集合和模型并将它们作为对象的属性返回,我还消除了从主应用程序文件中引用集合和模型的需要。这样,如果我需要一个新模型或集合,我只需要使用“relational.js”。

我的 relational.js 文件看起来有点像这样:

define([
  // Models
  "models/broadcast",
  "models/version",
  // Collections
  "collections/broadcasts",
  "collections/versions"

], function(
  // Models
  Broadcast,
  Version,
  // Collections
  Broadcasts,
  Versions
) {
  "use strict";

  var _relational = {
    Broadcast: Broadcast,
    Version: Version,  

    Broadcasts: Broadcasts,
    Versions: Versions,
  };

  // Register the Collections
  Backbone.JJRelational.registerCollectionTypes({
    "Broadcasts": _relational.Broadcasts,
    "Versions": _relational.Versions    
  });

  // Provide JJRelational with model scope - pull request submitted to JJRelational to handle this
  Backbone.JJStore.addModelScope(_relational);

  return _relational;
});

然后在我的主 app.js 中:

define(["libs/relational"], function(Relational){
  var broadcast = new Relational.Broadcast();
});

【讨论】:

    【解决方案2】:

    你有没有推荐过Backbone Associations。我建议你看一次。

    当我使用它时,我遇到过类似的循环依赖和自引用问题。原因是我已将客户端的Models 映射到后端的Beans,然后使用Hibernate 映射到Tables。当您在Hibernate 中指定one-to-many 关系时,您需要指定一个实体对另一个实体的引用,反之亦然。然后,当 Jersey 服务返回这些实体时,向 JSON 的转换具有循环依赖关系。我可以使用some annotations 在后端摆脱它。但是没有办法在Backbone 方面解决它。我向Backbone Associations 的作者提出了这个问题,他们修复了它。

    希望这对您有所帮助。

    【讨论】:

    • 感谢您的评论和建议另一个图书馆
    猜你喜欢
    • 2012-12-02
    • 2023-03-04
    • 2019-11-06
    • 1970-01-01
    • 1970-01-01
    • 2014-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多