如何用 AngularJS 影响 HTML 渲染优先级?

How to impact the HTML rendering priorities with AngularJS?

我正在通过 PhantomJS 通过 Selenium 为搜索引擎机器人预呈现我的 HTML 页面,以便他们可以看到完全加载的内容。目前,在 PhantomJS 到达页面后,我正在等待 5 秒,以便确定所有内容都已加载。

与其每次都等待这 5 秒,我考虑的一种解决方案是等到 <body /> 标记上的属性 html-ready 设置为 true:

<html ng-app>
    <head>...</head>
    <body html-ready="{{htmlReady}}">
        ...
    </body>
</html>
.controller("AnyController", function($scope, $rootScope, AnyService) {
    $rootScope.htmlReady = false;
    AnyService.anyLongAction(function(anyData) {
        $scope.anyData = anyData;
        $rootScope.htmlReady = true;
    });
})

问题是:在完成 任何视图更新(例如显示 anyData)后,html-ready 属性是否始终设置为真 ?换句话说,有没有可能在一圈中,html-ready属性是true,而页面还没有完全加载?如果是,如何处理?

简答

没有。设置 html-ready 后,无法保证您的标记将完全呈现。

长答案

据我所知,无法准确确定模型更改后 Angular 何时完成更新 DOM。一般来说,它发生得非常快,不需要超过几个周期就可以完成,但情况并非总是如此。

正确检测页面何时完成 loading/rendering 实际上是一个相当大的挑战,如果您查看专用工具的源代码,例如 prerender,您会发现它们使用几种不同的检查来尝试 来决定页面是否准备就绪。即便如此,它也不会在 100% 的时间内正常工作(Phantom 可能会崩溃,请求可能需要比平时更长的时间才能完成,等等)。

如果你真的想针对这个问题提出自己的解决方案,我建议你看一下prerender的源代码(或其他类似的项目)以获得一些灵感。

它应该在摘要之后完成,这样它有更多的机会按预期工作。

AnyService.anyLongAction(function(anyData) {
    $scope.anyData = anyData;
    $timeout(function () {
        $rootScope.htmlReady = true;
    }, 0, false);
});

但在应用程序方面是没有用的。您必须注意每个地方的变化,Angular 没有提供任何使任务更容易的东西。

幸运的是,您可以从 Angular 中自由抽象并保持简单。

var ignoredElements = [];
ignoredElements = ignoredElements.concat($('.continuously-updating-widget').toArray());

var delay = 200; // add to taste
var timeout;

var ready = function () {
  $('body').off('DOMSubtreeModified');
  clearTimeout(timeoutLimit);
  alert('ready');
};

$('body').on('DOMSubtreeModified', function (e) {
  if (ignoredElements.indexOf(e.target) < 0) {
    clearTimeout(timeout);
    timeout = setTimeout(ready, delay);
  }
});

var timeoutLimit = setTimeout(ready, 5000);

尽管它不是生产代码,但如有需要,请随意调整它。

将处理程序放入 throttle wrapper 函数中是个好主意(事件将一直发送垃圾邮件)。如果您在页面上使用可能超过超时延迟的远程请求,最好将此方法与异步服务的几个承诺结合起来,并使用 $q.all 解决它们。不过,总比照顾好每一个指令和服务要好得多。

DOMSubtreeModified被认为是过时的(它从未被真正承认,MutationObserver被推荐),但当前版本的FF和Chrome支持它,它应该是对硒没问题。