code: function destroyViewTree(rootView) {
      // If the view has no children, we can clean it up and return early.
      if (rootView[TVIEW].childIndex === -1) {
          return cleanUpView(rootView);
      }
      var viewOrContainer = getLViewChild(rootView);
      while (viewOrContainer) {
          var next = null;
          if (viewOrContainer.length >= HEADER_OFFSET) {
              // If LViewData, traverse down to child.
              var view = viewOrContainer;
              if (view[TVIEW].childIndex > -1)
                  next = getLViewChild(view);
          }
          else {
              // If container, traverse down to its first LViewData.
              var container = viewOrContainer;
              if (container[VIEWS].length)
                  next = container[VIEWS][0].data;
          }
          if (next == null) {
              // Only clean up view when moving to the side or up, as destroy hooks
              // should be called in order from the bottom up.
              while (viewOrContainer && !viewOrContainer[NEXT] && viewOrContainer !== rootView) {
                  cleanUpView(viewOrContainer);
                  viewOrContainer = getParentState(viewOrContainer, rootView);
              }
              cleanUpView(viewOrContainer || rootView);
              next = viewOrContainer && viewOrContainer[NEXT];
          }
          viewOrContainer = next;
      }
  }
docs: Traverses down and up the tree of views and containers to remove listeners and
  call onDestroy callbacks.
  
  Notes:
  - Because it's used for onDestroy calls, it needs to be bottom-up.
  - Must process containers instead of their views to avoid splicing
  when views are destroyed and re-added.
  - Using a while loop because it's faster than recursion
  - Destroy only called on movement to sibling or movement to parent (laterally or up)
  
  @param rootView The view to destroy