• Flash & Flex组件优化的杀手锏callLater


    Flash的fl组件和Flex的mx组件都有一个受保护方法callLater,callLater可以说是优化组件执行效率的一个杀手锏,极其有用。

    拿Flash的fl组件为例,fl组件有个重绘方法redraw(),如果改变组件的大小,焦点的获得和丢失都会是组件重绘来呈现不同的状态。而组件是复杂的,重绘的开销很大。如果假想一个按钮执行以下程式来更改外观,并且每次的更改都触发redraw()方法执行,那它将执行3次重绘,很显然是不须要的。

    button.width=200
    ;
    button.
    height=28
    ;
    button.
    setStyle("textFormat",myTextFormat);

    一个优化的方式是假设组件不会自动重绘,需要手动进行:

    button.width=200
    ;
    button.
    height=28
    ;
    button.
    setStyle("textFormat",myTextFormat)
    ;
    button.redraw
    ();

    这个方式不太友好,每次都要记得去重绘组件,幸运的是callLater解决了这个问题。

    callLater把要执行的函数延迟到下一帧。所以对button的width更改后,它会记得在下一帧重绘自身,当然这一帧你还改变了height和样式,它也只是重复地记忆要在下一帧重绘自身。到了下一帧的时候,它执行一次redraw(),仅是一次。

    Flex组件的基类UIComponent有110多个公开属性,90个公开方法,17个受保护方法,70多个事件,10多个样式,10多个效果,还有6个常量。一个基类都如此庞大,可想而知,优化是多么重要。
    在Flex组件的callLater中,重绘被分割成了三个受保护的方法:

  • commitProperties()
  • measure()
  • updateDisplayList()
  • 职责的分割更加提高了效率,这些延迟执行都是callLater实现的。把callLater实现的细节抽取下来写成一个单独的类:

    package com.colorhook.tools{ 
    /**
    * @author colorhook
    * @copyright http://www.colorhook.com
    */
     
     
    import flash.display.DisplayObject
    ;
     
    import flash.utils.Dictionary
    ;
     
    import flash.events.Event
    ;
     
     
    public class FrameCallLater implements ICallLater{
     
     
    private var _target:DisplayObject
    ;
     
    private var methods:Dictionary
    ;
     
    private var inCallLaterPhase:Boolean=false
    ;
     
     
    public function FrameCallLater(target:DisplayObject){ this._target=target
    ;
            methods=
    new Dictionary(true)
    ;
     
    super()
    ;
     
    }
     
     
    /**
         * defined by ICallLater, I write a class TimeCallLater to implement it also.
         */
    public function call(fun:Function):void{ if (inCallLaterPhase||_target==null) { return; }
     
            methods
    [fun]=true
    ;
     
     
    if (_target.stage != null) {            _target.stage.addEventListener(Event.RENDER,callLaterDispatcher,false,0,true)
    ;
                _target.
    stage.invalidate()
    ;
     
    } else {            _target.addEventListener(Event.ADDED_TO_STAGE,callLaterDispatcher,false,0,true)
    ;
     
    } }
     
     
    private function callLaterDispatcher(event:Event):void { if (event.type == Event.ADDED_TO_STAGE) {            _target.removeEventListener(Event.ADDED_TO_STAGE,callLaterDispatcher)
    ;
                _target.
    stage.addEventListener(Event.RENDER,callLaterDispatcher,false,0,true)
    ;
                _target.
    stage.invalidate()
    ;
     
    return
    ;
     
    } else {            event.target.removeEventListener(Event.RENDER,callLaterDispatcher)
    ;
     
    if (_target.stage == null) {                _target.addEventListener(Event.ADDED_TO_STAGE,callLaterDispatcher,false,0,true)
    ;
     
    return
    ;
     
    } }
     
            inCallLaterPhase =
    true
    ;
     
     
    for (var method:Object in methods) { method()
    ;
     
    delete(methods[method])
    ;
     
    }        inCallLaterPhase = false
    ;
     
    }
     
     
    public function get target():DisplayObject{ return
    _target;
     
    }} }

    分享到:


     
  • 相关阅读:
    如何用纯 CSS 创作一个蝴蝶标本展示框
    如何用纯 CSS 创作一个菱形 loader 动画
    如何用纯 CSS 创作背景色块变换的按钮特效
    如何用纯 CSS 绘制一个充满动感的 Vue logo
    css实现盒尺寸重置、均匀分布的子元素、截断文本
    Wireshark分析RabbitMQ
    MVC5 一套Action的登录控制流程
    MySQL timespan设置 sql_mode设置
    MVC webapi,Action的分别拦截器
    CentOS7.2 安装RabbitMQ3.6.10
  • 原文地址:https://www.cnblogs.com/kakafra/p/2749722.html
  • Copyright © 2020-2023  润新知