Search code examples
angulardomangular2-changedetection

Angular2 - heavy computation + loader show / hide - my DOM doesn't match what's on the page


I'm working in Angular 2, trying to show a loader before a heavy computation and hiding it afterward. When I show the loader, the DOM is updating, but the view is not repainting. Therefore, my loader never appears.

Full code is here.

How is this possible?


Solution

  • The Issue

    The issue was that my browser was freezing from the heavy computation. The browser didn't have a chance to repaint after I showed the loader, because when it tried to repaint, the heavy computation was blocking the stack.


    What we want on the stack

    1. Loader reveal
    2. Browser repaint
    3. Heavy computation
    4. Loader hide
    5. Browser repaint

    In other words, we want to ensure the loader reveal goes on the stack BEFORE the heavy computation (I will call this function "H") goes on the stack, so that "H" doesn't block the stack while the browser tries to repaint.


    How we get this on the stack

    I figured out the solution by watching a brilliant video about asynchronicity / event loops / task queues / etc.

    The solution is:

    <loader-show>
    setTimeout(() => {
       <heavy-computation>
       <loader-hide>
    }, 20)
    

    wrap both "H" and the loader hide inside a setTimeout. This way, the loader reveal will go on the stack, then "H" and loader hiding will go to the task queue, and will only be pushed onto the stack (executed) when the stack is empty (ie. after loader reveal).

    BUT notice the "20" ms delay in setTimeout? Another critical element from the video is that

    the browser repaints every 16 milliseconds

    meaning that my setTimeout has to delay by >16 seconds in order to ensure that the browser will repaint the view before "H" executes and blocks the stack.


    Other Tips

    • Move your heavy computation to the backend.
    • Use a CSS-based loader.

    Reference Code

    Here is the solved code.