0

I have a big angularjs html page, the rendering of angularjs will take a lot of time. So the page is almost blank at first, and after a while, it shows everything suddenly.

I wonder if there is any way to make the fast part shows first, and the slow part will show later, so the user won't be surprised by a blank page.

I made a simple demo:

<!DOCTYPE html>

<html ng-app>
<head>
    <meta charset="UTF-8">
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.js"></script>
</head>
<body ng-controller="Ctrl">
<button ng-click="go()">Go</button>
<hr/>
<div>Fast</div>
<button ng-repeat="name in fastNames">{{name}}</button>
<hr/>
<div>Slow</div>
<button ng-repeat="name in slowNames">{{name}}</button>
</body>
</html>
<script type="text/javascript">
    function Ctrl($scope) {
        $scope.fastNames = [];
        $scope.slowNames = [];

        $scope.go = function () {
          $scope.fast();
          $scope.slow();
        }

        $scope.fast = function() {
          $scope.fastNames = ["F1", "F2"];
        };

        $scope.slow = function() {
          for (var i = 0; i < 50000000; i++) {
            new Date();
          }
          $scope.slowNames = ["S1", "S2"];          
        }


    }
</script>

You can see there are two parts -- "fast names" and "slow names". I hope the fast names can show as soon as possible, then the slow names. But for now, they won't show at first, and after a while, they show together.

I created a live demo: http://plnkr.co/edit/9lW2TbLBkCB1hhgBVGmo?p=preview

What should I do?

Freewind
  • 193,756
  • 157
  • 432
  • 708
  • Until go() returns, the view won't update. Split your go() function up into two pieces: gofast() and goslow(). Call goslow() in a timeout or something to allow gofast() to return before goslow() starts. – Mark Rajcok Feb 21 '13 at 04:20
  • It seems work: , but is it the "angularjs way" to do it? I need to add a `$scope.$digest()` manually. – Freewind Feb 21 '13 at 04:28
  • I just found it works on chrome, but not on firefox. – Freewind Feb 21 '13 at 04:31
  • Use the `$timeout` service, you won't need to call `$digest`. You can then just do `$timeout($scope.slow)`. – satchmorun Feb 21 '13 at 04:34
  • Thank you, it works on chrome. Still not working well on firefox? – Freewind Feb 21 '13 at 04:54

1 Answers1

2

As mentioned in the comments, the browser won't get a chance to render until go() returns (JavaScript is single-threaded). Split up the go() function and put the slow part into a separate function that is called asynchronously, via $timeout. To ensure the browser has a chance to render before calling the $timeout callback, give the $timeout a delay of say 50ms.

$scope.go = function () {
   $scope.fast();
   $timeout(function() {
      $scope.slow();
   },50);  // give browser time to render
};

Plunker

Pieter Herroelen
  • 5,977
  • 2
  • 29
  • 37
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • How to determine the best timeout delay? Is `50ms` always working for the major browsers? – Freewind Mar 10 '13 at 03:19
  • 1
    @Freewind, there is no way to know for sure when the browser has finished rendering. In this post http://stackoverflow.com/questions/11125078/is-there-a-post-render-callback-for-angular-js-directive, Nic periodically checked something in the DOM to determine if rendering was complete. – Mark Rajcok Mar 10 '13 at 03:26