【问题标题】:Wait for changes to be applied in AngularJS / general javascript?等待在 AngularJS / 通用 javascript 中应用更改?
【发布时间】:2014-03-04 22:58:45
【问题描述】:

我正在将 AngularJS 用于应用程序,但在将更改推送到视图时遇到了某些问题。

用例

当我对视图/数据(xhr 请求、恢复状态和批次)进行重大更新时,我会向用户显示加载器 gif。我使用绑定到 img 标记的标志(使用 ngClass),因此在设置标志时会显示加载程序 gif。该标志也用作锁(不是以线程安全的方式,但足以应付手头的任务)。我在启动进程时获取锁(设置标志),并在所有 xhr 调用的最后一个承诺 ($q) 解决后释放它。

问题

当我使用 HTML5 历史 API 恢复数据并从服务器加载数据(重新加载、向前或向后)时,视图可能需要相当长的时间来反映对模型所做的更改。由于我只依赖于 http 请求的承诺,因此我的加载程序 gif 在视图(可见)更新之前被隐藏。有没有办法检测更改何时对用户可见,而不是观察模型更改?这可能不再是 Angular 问题,而是一般的 JS 问题。

时间线

(1) 设置标志->

(2) 执行 xhr/model 更改 ->

(3) 释放锁->

(4) AngularJS 应用完毕 ->

(5) 变化可见

问题主要存在于第 4 步和第 5 步之间(还有第 3 步和第 4 步,但这实际上并不明显)。

示例

作为用户,我可以清楚地看到正在生成的表格行,但表格单元格仍然是空的。几十毫秒后,这些值出现。我不确定这是默认的 Angular 行为,还是我的浏览器无法足够快地呈现对 HTML 的更改。

我的想法

我猜这个问题与浏览器更新视口的方式交织在一起。我还没有真正深入研究,但在我看来,Angular 已经实际应用了这些更改,但它们还没有被浏览器呈现。使用指令监视 $last 标志的主数据表,我可以检测到 ng-repeat 完成和可见呈现视图之间的相当大的延迟。可能是这对浏览器的细节太过分了,但也许其他人对此有一些想法可以分享:)

【问题讨论】:

  • 请发布一些代码。也许你需要运行 $scope.$apply
  • AngularJS 应用模型的更改没有问题。所有数据都在最后的视图中正确表示。问题在于 AngularJS 完成应用和浏览器有效呈现新 HTML 之间的明显延迟。我已经包含了一个时间线和一个示例来澄清。
  • 只是为了跟进我对浏览器存在性能问题的想法:在(最终)获得似乎摆脱了 FireBug 错误的 Firefox 更新之后,我可以确认这个错误在最少增加延迟的严重性。我仍然需要使用 HarishR 和 package 提到的技巧,但现在肯定更好。

标签: javascript html angularjs browser render


【解决方案1】:

你可以有最低优先级的指令......例如-1 并使用该指令显示或隐藏 spinner/gif 元素

作为优先级最低的指令,它将在视图更新中最后执行。所以 show-spinner 在这个指令的一部分可以是假的,因此 spinner 只会在所有的变化都被渲染后才会隐藏......

PLUNKER LINK

【讨论】:

  • 据我所知,优先级排序指令在单个元素上,而不是当前在 DOM 中的所有指令。鉴于加载器 gif 位于带有 DOM 数据的 table 元素上方的元素上,在这种情况下优先级会产生任何影响吗?
  • @package:据我所知,它在 DOM 中,这就是 ng-cloak 指令的工作原理......但是用 plunk 确认这一点
  • @package: 添加插件链接
  • 是的,你完全正确。我指的是文档:When there are multiple directives defined on a single DOM element, sometimes it is necessary to specify the order in which the directives are applied.,但这显然不是真的。
【解决方案2】:

这可能有点骇人听闻,但我遇到了外部库必须将事件侦听器附加到ngRepeat 生成的元素的情况。显然,当模型观察者触发时元素还没有出现,所以我所做的是对ngRepeat 元素的自定义指令,它将观察ngRepeat$last 属性,然后将$evalAsync 需要回调。思路是这样的:

.directive('onRepeatFinish', function() {
  return {
    restrict: 'A',
    link: function(scope, element, attributes) {
      if (scope.$last === true) {
        scope.$evalAsync(attributes.onRepeatFinish);
      }
    }
  };
})

考虑到这一点,您可以隐藏加载器图像,而不是在释放锁时,而是当某个事件,比如renderComplete,由该指令发送时。

模板:

<div ng-repeat="record in data" on-repeat-finish="$emit('renderComplete')"></div>

$rootScope 中的处理程序:

.run(function($rootScope) {
  $rootScope.$on('renderComplete', function(){
    $rootScope.showLoader = false;
  })
})

【讨论】:

    猜你喜欢
    • 2016-03-25
    • 2018-02-28
    • 2012-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多