javascript - 单页应用程序SEO和无限滚动AngularJS

标签 javascript angularjs performance mobile

我们有一个网站,其提要类似于pinterest,并且正计划将jquery汤重构为更结构化的内容。两种最可能的候选人是AngularJS和Backbone + Marionette。该网站是由用户创建的,并且大多以消费为导向(通常为90/9/1规则),用户可以对帖子进行喜欢,添加书签和评论。在提要中,我们打开一个灯箱,以查看有关带有​​评论的帖子的更多详细信息,相关帖子,类似于pinterest。

我们偶尔使用主干,对此想法很熟悉,但被样板推迟了。我认为“木偶戏”将对此有很大帮助,但如果长期来看会有所帮助,我们愿意更彻底地改变方向(例如Angular)。

要求:

  • 由于SEO的原因,初始页面必须是静态的。框架必须能够从现有内容开始,而无需花费太多精力,这一点很重要。
  • 我们希望将Feed所需的灯箱数据加载到Feed中,以便可以更快地进行转换。一些数据已经存在(标题,描述,照片,喜欢的数字/喜欢的书签,评论数量),但是将为详细 View 加载其他数据-评论,类似的帖子,喜欢的人,等等。
  • 供稿或详细信息灯箱中发生的帖子更改应在其他工作中反射(reflect)出来(例如,如果我喜欢供稿,则转到灯箱时,我应该看到计数和新计数)-或相反。)
  • 我们想迁移我们的移动站点(当前在Sencha Touch中),以对相同的部分也使用相同的代码库,以便我们可以在移动站点和主站点之间实现更紧密的功能对等。

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

    1)通过模板增加页面时,初始页面加载是否可能是静态的/是否有问题。

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

    3)双向绑定(bind)很酷-我担心这对我们来说可能是负面的,因为要渲染的项目数量很多。我们需要双向绑定(bind)的元素数量相对较少。像这样的帖子:
  • https://stackoverflow.com/a/7654856/214545
  • Angular JS ng-repeat consumes more browser memory

  • 关注我的用例。我们可以轻松地拥有数百个帖子,每个帖子具有1-2打细节。在我知道不会更改的字段/元素中,可以将双向绑定(bind)“禁用”吗?

    将 View 端口外部的元素卸载到同一内存是否正常/可行?这也与移动方向相关,因为那里的内存甚至更多。

    AngularJS在我们的用例中能否很好地工作/执行?是否有任何技巧/提示对您有帮助?

    最佳答案

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

    您会在这里遇到性能的地方牺牲可用性。

    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. 使用限制来附加 Assets

    在这里,我们建议用户可以继续在供稿中显示更多结果,这些供稿将无限追加,但必须节制或“手动”调用更多数据的调用。相对于用户将滚动浏览的内容的大小而言,这变得很麻烦。

    如果每个有效负载有很多内容被撤消,则用户将不得不少点击“获取更多”按钮。当然,这是在返回更大的有效载荷的权衡下。
    <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操作仅作用于配置中指定的当前范围。但是,这有其自身的陷阱。

    最大的是跨设备兼容性。

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

    其次是可靠性。如果用户手动将滚动条从低索引拖动到极高的索引,则将迫使浏览器非常快速地运行这些指令,这在测试中导致我的浏览器崩溃。这可以通过隐藏滚动条来解决,但是用户当然可以通过非常快速地滚动来调用相同的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."
    因此,您要说的是要在页面提供内容之前将页面预渲染到服务器端吗?这种方法在成千上万的早期就行之有效,但是大多数人都在朝着单页应用程序风格的方向发展。有充分的理由:
  • 发送给用户的初始种子充当 bootstrap 来获取API数据,因此您的服务器可以减少工作量。
  • 延迟加载 Assets 和异步Web服务调用使感知的加载时间比传统的“首先呈现服务器上的所有内容,然后将其返回给用户的方法”要快得多。
  • 您可以通过使用页面预渲染/缓存引擎保留在您的SEO上,该引擎位于您的Web服务器的前面,以仅响应具有“完全渲染版本”的Web爬网程序。 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的初始有效负载不包含每个“feed ID”的子数据点,并且需要使用其他API请求将其加载到灯箱中,则您做对了。这完全是一个合法的用例。您可能会为单个API调用争辩50-100ms,这对于最终用户来说是无法感知的延迟。如果您确实需要在Feed中发送其他有效载荷,那么您将无法赢得很多 yield 。
    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.)
    您在这里混合技术--- like按钮是对Facebook的API调用。这些更改是否会导致同一页面上的其他类似按钮的实例化取决于Facebook如何处理它,我相信快速的Google会为您提供帮助。

    但是,特定于您网站的数据---有两种不同的用例:
  • 说我在灯箱中更改标题,并且还希望更改能够传播到当前显示在其中的供稿。如果将“保存编辑操作” POST发送到服务器,则成功回调可能会触发使用websocket更新新值。此更改不仅会影响您的屏幕,还会影响其他所有人的屏幕。
  • 您可能还讨论了双向数据绑定(bind)(AngularJS非常擅长于此)。通过两种方式进行数据绑定(bind),可以将“模型”或从Web服务获取的数据绑定(bind)到 View 中的多个位置。这样,当您编辑共享同一模型的页面的一部分时,另一部分将实时更新。这是在任何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就是蛋糕。这个想法是,您可以将您的网站组件导出到可以用于另一个项目的模块中。这也可以包括 View 。而且,如果您使用响应式框架构建 View ,请猜测一下-您现在可以在任何地方使用它。
    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.
    再次,这正是行业正在进入的 Realm 。使用将读取所有外部API数据的初始静态 bootstrap ,可以节省“实际”和“实际”的加载时间-这还将使您的开发周期更快,因为您将完全独立的Pepes的关注点分开了。您的API不需要关心您的 View ,而您的 View 也不需要关心您的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中的每个新结果集有关的工作。

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

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

    关于javascript - 单页应用程序SEO和无限滚动AngularJS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17258562/

    相关文章:

    c++ - 为什么 C++ STL 不实现更高效的 std::set 实现?

    asp.net - http 304 和 404 之间有什么性能差异吗?

    javascript - AngularJS 混合来自不同模块的同名 Controller

    javascript - 在 FireFox 中调整容器大小时(通过 javascript - jQuery),我的闪存重新初始化(重新加载)

    javascript - 剑道卡住(锁定)网格高度

    angularjs - 将 Angular-fullstack 部署到 Azure

    javascript - 移动字形图标切换菜单 Bootstrap

    javascript - 通过 url 传递的加密文本不解码 Javascript

    javascript - 生成图像后加载图像

    c# - C# 中的插值 - 性能问题