Flex tree expand slowly/lazy 超过30000个节点时加载

Flex tree expand slowly/lazy loading when there are more than 30000 nodes

我想以 UI 始终响应的方式打开 Flex mx Tree 的所有节点。通常当节点数量有限时,这段代码就可以正常工作。

public function expandAllNodes():void {
  for (var i:int = 0; i < this.dataProvider.length; i++) {
    expandChildrenOf(this.dataProvider.getItemAt(i), true);
  }
}

也许我需要callLater而不是直接调用函数

public function expandAllNodes():void {
  for (var i:int = 0; i < this.dataProvider.length; i++) {
    calllater(expandChildrenOf,[this.dataProvider.getItemAt(i), true]);
  }
}

但这也不起作用。

在这种情况下使用 callLater 无济于事。来自documentation,

The callLater method queues an operation to be performed for the next screen refresh, rather than in the current update.

在您的循环中使用 callLater 只会将 all expandChildrenOf() 调用推送到下一个屏幕刷新 - 这仍然会在单个更新周期中投入太多工作。

相反,您可以将循环分布在多个帧上并限制每帧完成的工作:

private var processingLimit:int = 10; //experiment to get a reasonable value for this
private var totalNodes:int = 0;
private var nodesProcessed:int = 0;

public function expandAllNodes():void {
    this.totalNodes = this.dataProvider.length;
    this.addEventListener(Event.ENTER_FRAME, expandNextNode);
}

private function expandNextNode(e:Event):void {
    var numToProcess = Math.min(processingLimit + nodesProcessed, totalNodes);
    for (var i:int = nodesProcessed; i < numToProcess; i++) {
        nodesProcessed++;
        expandChildrenOf(this.dataProvider.getItemAt(i), true);
    }

    if (numToProcess == totalNodes) {
        this.removeEventListener(Event.ENTER_FRAME, expandNextNode);
    }
}

n.b。确保 expandChildrenOf 不会递归地打开子项的子项——如果是这样,那么您仍然可以根据对 expandChildrenOf(1);!

的单次调用来展开整个树。

我就是这样解决问题的

private const PROCESSING_LIMIT:int = 25; 
public var _expandNodesStack:Vector.<Object>;
private function expandNextNode(e:Event):void {
  for (var i:int = 0; i < PROCESSING_LIMIT; i++) {
    var item:* = _expandNodesStack.pop();
    if (item)
      expandItem(item, true);
    else
      break;
  }
  if (_expandNodesStack.length == 0) {
    this.removeEventListener(Event.ENTER_FRAME, expandNextNode);
  }
}



public function expandAllNodes():void {
  if(this.dataProvider == null || this.dataProvider.length <= 0) return;
  if (_expandNodesStack != null && _expandNodesStack.length > 0) {
    //already expanding so abort this operation
    return;
  }
  if (_expandNodesStack == null) _expandNodesStack = new <Object>[];
  iterateAndPushToStack(this.dataProvider.getItemAt(0));
  _expandNodesStack.reverse();

  this.addEventListener(Event.ENTER_FRAME, expandNextNode);
}

private function iterateAndPushToStack(item:Object):void {
  if (iterator == null)
    return;

  // if it is not a branch item there's nothing to do
  if (item != null && item.children is ArrayCollection && item.children.length > 0) {
    _expandNodesStack.push(item);
    var childItems:ArrayCollection;
    childItems = item.children;
    if (childItems) {
      for each (var object:Object in childItems) {
        iterateAndPushToStack(object);
      }
    }
  }
}