Backbone.js 模型关系:加快性能

发布于 2024-12-10 18:34:50 字数 2510 浏览 0 评论 0原文

我有三个关联模型:Segments 每个都有两个 GeoPoints,关联存储为 GeoPointOnSegments。在服务器端,这是简单的 Rails 代码,具有 has_many :through 关系。在客户端,以下是我编写的Backbone代码。 (注意:我允许客户端创建数据,然后批量上传;这就是为什么有一些逻辑来处理本地和服务器 ID。)

我发现的问题是,当我有数百个数据时,此代码非常慢模型。具体来说,它是 geo_point.coffee 中的以下行:

masterRouter.geo_point_on_segments.select ...

对每个 GeoPointOnEntry 模型进行过滤,以便找到哪些模型连接到给定的 GeoPoint。 (请注意,可以有多个段连接到一个 GeoPoint。)对于如何提高性能有什么建议吗?

我的想法:

还有其他更好的想法吗?

geo_point.coffee

class App.Models.GeoPoint extends Backbone.Model
  name: 'geo_point'
  getGeoPointOnSegments: ->
    masterRouter.geo_point_on_segments.select (gpos) =>
      if @isNew()
        return gpos.get('geo_point_cid') == @cid
      else 
        return gpos.get('geo_point_id') == @id
    , this
  getSegments: ->
    _.compact _.map @getGeoPointOnSegments(), (gpos) =>
      gpos.getSegment() unless gpos.get('markedForDelete')
  getConnectedGeoPoints: ->
    _.compact _.flatten _.map @getSegments(), (s) =>
      s.getGeoPoints() unless s.get('markedForDelete')

geo_point_on_segment.coffee

class App.Models.GeoPointOnSegment extends Backbone.Model
  name: 'geo_point_on_segment'
  getGeoPoint: ->
    if local = masterRouter.geo_points.getByCid(@get 'geo_point_cid')
      return local
    else if server = masterRouter.geo_points.get(@get 'geo_point_id')
      return server
  getSegment: ->
    if local = masterRouter.segments.getByCid(@get 'segment_cid')
      return local
    else if server = masterRouter.segments.get(@get 'segment_id')
      return server

segment.coffee

class App.Models.Segment extends Backbone.Model
  name: 'segment'
  getGeoPointOnSegments: ->
    _.compact masterRouter.geo_point_on_segments.select (gpos) =>
      if gpos.isNew()
        return gpos.get('segment_cid') == @cid
      else if gpos.get('markedForDelete')
        return null
      else
        return gpos.get('segment_id') == @id
    , this
  getGeoPoints: ->
    _.map @getGeoPointOnSegments(), (gpos) =>
      gpos.getGeoPoint() unless gpos.get('markedForDelete')

I have three associated models: Segments each have two GeoPoints, with associations stored as GeoPointOnSegments. On the server side this is straightforward Rails code, with a has_many :through relationship. On the client side, the following is the Backbone code I have written. (A note: I allow for client-side creation of data and then batch upload; that's why there is some logic to deal with both local and server ids.)

The problem I am finding is that this code is very slow when I have hundreds of models. Specifically it's the following line in geo_point.coffee:

masterRouter.geo_point_on_segments.select ...

That's doing a filter on every single GeoPointOnEntry model in order to find which ones are connected to a given GeoPoint. (Note that there can be more than one Segment connected to a GeoPoint.) Any suggestions for how to improve performance?

Ideas I have had:

  • Make use of functionality provided by https://github.com/PaulUithol/Backbone-relational assuming that has something to offer
  • On the server-side, produce nested JSON, perhaps with some redundancy.
  • Create a client-side index of sorts with a JavaScript hash.

Have any other, better ideas?

geo_point.coffee

class App.Models.GeoPoint extends Backbone.Model
  name: 'geo_point'
  getGeoPointOnSegments: ->
    masterRouter.geo_point_on_segments.select (gpos) =>
      if @isNew()
        return gpos.get('geo_point_cid') == @cid
      else 
        return gpos.get('geo_point_id') == @id
    , this
  getSegments: ->
    _.compact _.map @getGeoPointOnSegments(), (gpos) =>
      gpos.getSegment() unless gpos.get('markedForDelete')
  getConnectedGeoPoints: ->
    _.compact _.flatten _.map @getSegments(), (s) =>
      s.getGeoPoints() unless s.get('markedForDelete')

geo_point_on_segment.coffee

class App.Models.GeoPointOnSegment extends Backbone.Model
  name: 'geo_point_on_segment'
  getGeoPoint: ->
    if local = masterRouter.geo_points.getByCid(@get 'geo_point_cid')
      return local
    else if server = masterRouter.geo_points.get(@get 'geo_point_id')
      return server
  getSegment: ->
    if local = masterRouter.segments.getByCid(@get 'segment_cid')
      return local
    else if server = masterRouter.segments.get(@get 'segment_id')
      return server

segment.coffee

class App.Models.Segment extends Backbone.Model
  name: 'segment'
  getGeoPointOnSegments: ->
    _.compact masterRouter.geo_point_on_segments.select (gpos) =>
      if gpos.isNew()
        return gpos.get('segment_cid') == @cid
      else if gpos.get('markedForDelete')
        return null
      else
        return gpos.get('segment_id') == @id
    , this
  getGeoPoints: ->
    _.map @getGeoPointOnSegments(), (gpos) =>
      gpos.getGeoPoint() unless gpos.get('markedForDelete')

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

暮年慕年 2024-12-17 18:34:50

我认为最好不要在 Backbone 中使用关系模型 GeoPointOnSegment

我想要工作的结构是:

  • 每个点都有一个集合,其中包含它所属的段
  • 每个段都有一个包含点的集合/数组

如果当您从 JSON 实例化数据时,您执行以下操作,那么这很容易做到:

  • 初始化所有点
  • 初始化每个 GeoPointOnSegment 的所有段
  • ,将点添加到段的集合中,并将段添加到点的集合中。检索点和段的集合速度很快,因为它是通过 id 进行的(并通过 Backbone 进行索引)。

此外,当您创建新分段时,您必须维护这些关联。

它是客户端索引,但集成在模型中。

I think it is better not to have the relation model, GeoPointOnSegment, in Backbone.

The structure I would like to work is:

  • each point has a collection with the segments it belongs to
  • each segment has a collection/array with the points

This is easy to do if, when you instantiate your data from JSON, you do something like:

  • initialize all the points
  • initialize all the segments
  • for each GeoPointOnSegment, add the point to the segment's collection, and the segment to the point's collection. Retrieving the point's and the segment's collection is fast, as it's by id (and indexed by Backbone).

Also, when you create new segments, you have to maintain these associations.

It is a client-side index, but integrated in the models.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文