4

我们有一个站点,其提要类似于 pinterest,并计划将 jquery 汤重构为更结构化的东西。两个最有可能的候选者是 AngularJS 和 Backbone+Marionette。该网站是用户生成的,主要面向消费(典型的 90/9/1 规则),用户可以对帖子进行点赞、收藏和评论。从提要中,我们打开一个灯箱,以查看有关该帖子的更多详细信息,包括评论、相关帖子,类似于 pinterest。

我们偶尔使用过骨干网,并且熟悉这个想法,但被样板文件推迟了。我认为 Marionette 在这方面会有很大帮助,但如果从长远来看,我们愿意更彻底地改变方向(例如 Angular)。

要求:

  • 出于 SEO 原因,初始页面必须是静态的。框架能够从现有内容开始,这一点很重要,最好不用打架。
  • 我们希望灯箱所需的数据已经加载到 feed 中,这样过渡可以更快。一些数据已经存在(标题、描述、照片、点赞数/书签数、评论数),但还会为详细视图加载其他数据——评论、类似帖子、谁喜欢这个等。
  • 在提要或详细信息灯箱中发生的帖子更改应该通过很少的工作反映在另一个中(例如,如果我从提要中喜欢它,如果我去灯箱,我应该看到喜欢和新的喜欢计数 - 或反之。)
  • 我们希望迁移我们的移动网站(目前在 Sencha Touch 中),以便对常见的部分也使用相同的代码库,以便我们可以在移动网站和主网站之间实现更紧密的功能对等。

这些要求与我对 Angular 的担忧有关:

1)在通过模板渲染附加页面时,初始页面加载是否可能/有问题。

2) 对于页面的不同部分有多个数据源是否有问题 - 例如,主要帖子部分来自嵌入的 json 数据和来自提要中的“查看更多”,而额外的细节将来自不同的 ajax 调用。

3)虽然双向绑定很酷 - 我担心在我们的案例中它可能是负面的,因为要渲染的项目数量。我们需要双向绑定的元素数量比较少。像这样的帖子:

我关心我们的用例。我们可以轻松地拥有数百个帖子,每个帖子都有 1-2 打详细信息。双向绑定可以在我知道不会更改的字段/元素的情况下“禁用”吗?

将视口之外的元素卸载到同一内存是否正常/可能?这也与移动方向有关,因为那里的内存更受关注。

AngularJS 在我们的用例中会工作/表现良好吗?有什么技巧/提示可以帮助到这里吗?

4

2 回答 2

18

正如您所说,有不同的“无限滚动”或馈送方法。用户的需求和可接受的响应负载的大小将决定您选择哪一个。

您在遇到性能的地方牺牲了可用性,这似乎在这里。

1. 追加资产

此方法是您传统的追加到底部方法,如果用户到达当前滚动高度的底部,将进行另一个 API 调用以“堆叠更多”内容。这具有作为处理跨设备警告的最有效解决方案的好处。

正如您所提到的,此解决方案的缺点来自于用户不小心滚动内容时大量有效负载会淹没内存。没有油门。

<div infinite-scroll='getMore()' infinite-scroll-distance='0'>
  <ul>
    <li ng-repeate="item in items">
      {{item}}
    </li>
  </ul>
</div>

var page = 1;
$scope.getMore() = function(){ 
 $scope.items.push(API.returnData(i));
 page++;
}

2.使用节流阀附加资产

在这里,我们建议用户可以继续在将无限附加的提要中显示更多结果,但它们必须被限制或“手动”调用更多数据的调用。相对于用户将滚动浏览的返回内容的大小,这变得很麻烦。

如果每个有效负载有很多内容被重新传输,用户将不得不少点击“获取更多”按钮。这当然是以返回更大的有效载荷为代价的。

<div>
  <ul>
    <li ng-repeate="item in items">
      {{item}}
    </li>
  </ul>
</div>
<div ng-click='getMore()'>
  Get More!
</div>

var page = 1;
$scope.getMore() = function(){
  $scope.items.push(API.returnData(i));
  page++;
}

3. 虚拟卷轴

这是无限滚动的最后也是最有趣的方式。这个想法是您仅将一系列结果的渲染版本存储在浏览器内存中。也就是说,复杂的 DOM 操作仅作用于配置中指定的当前范围。然而,这有它自己的陷阱。

最大的是跨设备兼容性。

如果您的手持设备有一个达到设备宽度的虚拟滚动窗口 --- 它最好小于页面的总高度,因为您将永远无法使用它自己的滚动条滚动经过这个“提要”。您将“卡在”中间页面,因为您的滚动将始终作用于虚拟滚动提要,而不是包含提要的实际页面。

其次是可靠性。如果用户手动将滚动条从低索引拖动到极高的索引,则您将强制浏览器非常快速地运行这些指令,这在测试中导致我的浏览器崩溃。这可以通过隐藏滚动条来解决,但当然用户可以通过非常快速地滚动来调用相同的场景。

这是演示

来源

"Initial page must static for SEO reasons. It's important that the framework be able to start with existing content, preferable with little fight."

所以你的意思是你希望页面在提供内容之前在服务器端进行预渲染?这种方法在最初的数千人中运行良好,但大多数人都在远离这种方法并转向单页应用程序风格。有充分的理由:

  • 您发送给用户的初始种子充当获取 API 数据的引导程序,因此您的服务器可以减少工作量。

  • 延迟加载资产和异步 Web 服务调用使得感知加载时间比传统的“先在服务器上渲染所有内容,然后将其返回给用户的方法”快得多。

  • 您可以通过使用页面预渲染/缓存引擎来保留您的 SEO,该引擎位于您的 Web 服务器前面,仅使用您的“完全渲染版本”响应网络爬虫。这个概念在这里得到了很好的解释。

we would prefer to have the data needed for the lightbox loaded already in feed so that the transition can be faster. Some of the data is already there (title, description, photos, num likes/ num bookmarks,num comments) but there is additional data that would be loaded for the detail view - comments, similar posts, who likes this, etc.

如果您的 feed 的初始有效负载不包含每个“feed id”的子数据点,并且需要使用额外的 API 请求将它们加载到您的灯箱中 --- 您做对了。这完全是一个合法的用例。您会争论 50-100 毫秒的单个 API 调用,这对您的最终用户来说是无法察觉的延迟。如果您绝对需要在您的提要中发送额外的有效负载,那么您赢不了多少。

Changes to the post that happen in the feed or detail lightbox should be reflected in the other with little work (eg, if I like it from the feed, I should see that like and new like count number if I go to the lightbox - or the opposite.)

您在这里混合技术 --- 点赞按钮是对 facebook 的 API 调用。这些更改是否会传播到同一页面上 facebook like 按钮的其他实例化取决于 facebook 如何处理它,我相信快速谷歌会帮助你。

但是,特定于您网站的数据 --- 有几个不同的用例:

  • 假设我更改了灯箱中的标题,并且还希望将更改传播到当前显示的提要。如果您的“保存编辑操作”POST 发送到服务器,成功回调可能会触发使用 websocket 更新新值。这种变化不仅会传播到您的屏幕,还会传播到其他所有人的屏幕。

  • 你也可以谈论双向数据绑定(AngularJS 擅长于此)。通过双向数据绑定,您的“模型”或您从 Web 服务返回的数据可以绑定到视图中的多个位置。这样,当您编辑共享同一模型的页面的一部分时,另一部分将与它一起实时更新。这发生在任何 HTTP 请求之前,因此是一个完全不同的用例。

We would like to migrate our mobile site (currently in Sencha Touch) to also use the same code base for the parts that are common so we can have closer feature parity between mobile and main site.

你真的应该看看像BootstrapFoundation这样的现代响应式 CSS 框架。使用响应式网页设计的要点是,您只需构建一次网站即可适应所有不同的屏幕尺寸。

如果你在谈论功能模块化,AngularJS 是最重要的。这个想法是您可以将您的网站组件导出到可用于另一个项目的模块中。这也可以包括视图。如果您使用响应式框架构建视图,猜猜是什么——您现在可以在任何地方使用它。

1) Will it be possible/problematic to have initial page loads be static while rending via the templates additional pages.

如上所述,最好远离这些方法。如果您绝对需要它,模板引擎不关心您的有效负载是呈现在服务器端还是客户端。部分页面的链接将同样易于访问。

2) is it problematic to have multiple data-sources for different parts of page - eg the main post part comes from embedded json data and from "see more"s in the feed while the additional detail would come from a different ajax call.

同样,这正是该行业正在发展的方向。您将使用获取所有外部 API 数据的初始静态引导程序来节省“感知”和“实际”加载时间——这也将使您的开发周期更快,因为您将完全独立的部分分离。你的 API 不应该关心你的视图,你的视图也不应该关心你的 API。这个想法是,当您将 API 和前端代码分解成更小的部分时,它们都可以变得模块化/可重用。

3) While the two-way binding is cool - I'm concerned it might be a negative in our case because of the number of items being rendered. The number of elements that we need two-way binding is relatively small.

我还将把这个问题与你在下面留下的评论结合起来:

Thanks for the answer! Can you clarify - it seems that 1) and 2) just deal with how you would implement infinite scrolling, not the performance issues that might come from such an implementation. It seems that 3 addresses the problem in a way similar to recent versions of Sencha Touch, which could be a good solution

您将遇到的性能问题完全是主观的。我试图在讨论中概述诸如节流之类的性能注意事项,因为节流可以大大减少服务器承受的压力以及用户浏览器对附加到 DOM 的每个新结果集所做的工作。

一段时间后,无限滚动会耗尽您的用户浏览器内存。我可以告诉你的这些是不可避免的,但只有通过测试你才能知道有多少。根据我的经验,我可以告诉您,用户浏览器可以处理大量滥用行为,但同样,每个结果集的有效负载有多大以及您在所有结果上运行的指令都是完全主观的。在我描述的选项 3 中,有一些解决方案仅在范围数据集上呈现,但也有其局限性。

返回的 API 数据大小不应超过 1-2kbs,返回查询只需大约 50-200ms。如果您没有达到这些速度,也许是时候重新评估您的查询或通过使用子 ID 查询其他端点的详细信息来减少返回的结果集的大小。

于 2013-06-25T16:27:50.340 回答
0

丹的答案中仍未得到解答的主要问题是初始页面加载。我们仍然对我们必须在客户端执行此操作的方法不满意 - 在我们看来,SEO 和初始页面加载仍然存在风险。我们有相当多的 SEO 流量并且正在寻找更多流量——这些人来到我们的网站时没有缓存,我们有几秒钟的时间来捕捉他们。

有几个选项可以在服务器端处理 angular - 我将尝试在此处收集其中一些:

https://github.com/ithkuil/angular-on-server https://github.com/ithkuil/angular-on-server/wiki/Running-AngularJS-on-the-server-with-Node.js-and -jsdom

https://github.com/angular/angular.js/issues/2104

当他们出现时会添加更多。

于 2013-08-01T12:42:45.950 回答