单页应用SEO和无限滚动AngularJS

时间:2013-06-23 07:24:15

标签: javascript angularjs performance mobile

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

我们偶尔使用骨干并熟悉这个想法,但是在样板上推迟了。我认为木偶会对此有很大的帮助,但如果从长远来看,我们会更加彻底地改变方向(例如Angular)。

要求:

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

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

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

2)为页面的不同部分提供多个数据源是有问题的 - 例如,主要帖子部分来自嵌入的json数据和来自"在Feed中查看更多数据源,而附加细节将来自不同的ajax电话。

3)虽然双向绑定很酷 - 我担心在我们的情况下它可能是负面的,因为渲染的项目数量很多。我们需要双向绑定的元素数量相对较少。帖子如:

关注我的用例。我们可以轻松拥有数百个帖子,每个帖子有1-2个细节。双向绑定是否可以被禁用"我知道哪些领域/元素不会改变?

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

AngularJS会在我们的用例中运行良好吗?有什么技巧/提示可以帮助吗?

2 个答案:

答案 0 :(得分:17)

有不同的方法"无限滚动"或者按照你的意愿喂食。用户的需求和可接受的响应有效负载的大小将决定您选择哪一个。

你牺牲了可用性,而你在这里遇到了表现。

1。 Append assets

这种方法是你传统的追加到底层方法的方法,如果用户到达当前滚动高度的底部,将进行另一个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。使用限额附加资产

在这里,我们建议用户可以继续在无限追加的Feed中显示更多结果,但这些结果必须是节流或手动&#34;调用更多数据的调用。相对于用户将滚动的返回内容的大小,这变得麻烦。

如果每个有效负载都有很多内容被重新启动,那么用户必须单击&#34;得到更多&#34;按钮少。这当然是在返回更大的有效载荷时的权衡。

<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。 Virtual Scroll

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

最大的是跨设备兼容性。

如果您的手持设备有一个达到设备宽度的虚拟滚动窗口 - 它最好小于页面的总高度,因为您将永远无法滚动过去&#34; Feed&#34 ;有自己的滚动条。你会被困住#34;中间页面,因为您的滚动将始终作用于虚拟滚动Feed,而不是包含Feed的实际页面。

接下来是可靠性。如果用户将滚动条从低索引手动拖动到极高的索引,则会迫使broswer非常快速地运行这些指令,这在测试中导致浏览器崩溃。这可以通过隐藏滚动条来修复,但当然用户可以通过非常快速地滚动来调用相同的senario。

Here is the demo

The source

"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服务调用使得受影响的加载时间比传统的加载时间快得多,然后首先将服务器上的所有内容呈现出来,然后再将其反馈给用户方法。&#34;

  • 您的搜索引擎优化可以通过使用页面预渲染/缓存引擎保留在您的网络服务器前面,仅用您的&#34;完全渲染版本#34;来响应网页抓取工具。这个概念很好地解释了 here

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的初始有效负载不包含每个&#34; Feed id&#34;并且需要使用额外的API请求将它们加载到您的灯箱中 - 您做得对。这完全是一个合法的用例。对于单个API调用,您可能会争论50-100ms,这对您的最终用户来说是一个难以置信的延迟。如果您迫切需要使用您的Feed发送额外的有效负载,那么您不会赢得太多。

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按钮的其他实例是由facebook如何处理它,我确定快速谷歌会帮助你。

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

  • 假设我更改了灯箱中的标题,并希望更改传播到当前显示的Feed中。如果你的&#34;保存编辑操作&#34; POST到服务器后,成功回调可以触发使用websocket更新新值。这种变化不仅会传播到你的屏幕上,而且会让所有人都屏幕显示。

  • 你也可以谈论双向数据绑定(AngularJS很擅长)。通过双向数据绑定,您的&#34;模型&#34;或者您从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.

您应该真正了解一下现代响应式CSS框架,例如 Bootstrap Foundation 。使用响应式网页设计的关键是,您只需构建一次网站即可适应所有不同的屏幕尺寸。

如果您正在谈论功能模块化,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.

同样,这正是整个行业的发展方向。你将拯救&#34; percieved&#34;和&#34;实际&#34;使用初始静态引导加载时间来获取所有外部API数据---这也将使您的开发周期更快,因为您正在分离完全独立的peices的问题。您的API不关心您的观点,您的观点也不关心您的API。我们的想法是,当您将API和前端代码分解为更小的peices时,它们都可以变为模块化/可重用的。

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中的工作。

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

返回的API数据不应超过1-2kbs,并且只需要大约50-200ms即可返回查询。如果您不满足这些速度,请重新评估您的查询,或者通过使用子ID来查询返回的结果集的大小,以查询其他端点的详细信息。

答案 1 :(得分:0)

Dan的答案中仍未解决的主要问题是初始页面加载。我们仍然不满意我们必须在客户端做的方法 - 我们似乎仍然存在搜索引擎优化和初始页面加载的风险。我们有相当数量的搜索引擎优化流量,并寻找更多 - 这些人来到我们的网站没有缓存,我们有几秒钟赶上他们。

在服务器端有一些处理角度的选项 - 我会尝试在这里收集一些角色:

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

会在出现时添加更多内容。