JavaScript优化(三)

来源:互联网 发布:ping端口号 编辑:程序博客网 时间:2024/06/05 17:59

重绘与重排

浏览器下载完页面中的所有组件——HTML标记、JavaScript、CSS、图片——之后回解析并生成两个内部数据结构:

DOM树

    表示页面结构

渲染树

    表示DOM节点如何显示

重绘和重排操作都是代价昂贵的操作,它们会导致Web应用程序的UI反应迟钝。

重排何时发生?

  • 添加或删除可见的DOM元素
  • 元素位置改变。
  • 元素尺寸改变(包括:外边距、内边距、边框厚度、宽度、高度等属性改变)。
  • 内容改变,例如:文本改变或图片被另一个不同尺寸的图片代替。
  • 页面渲染器初始化
  • 浏览器窗口尺寸改变

每次重排都会产生计算消耗,因此一个好的提高程序响应速度的策略就是减少此类操作的发生。

改变样式

    考虑这个例子:

    var el = document.getElementById('mydiv');
    el.style.borderLeft = '1px';
    el.style.borderRight = '2px';
    el.style.padding = '5px';

最糟糕的情况下会导致浏览器触发三次重排(大多现代浏览器做了优化,只会触发一次)。而且,这段代码四次访问DOM。可以被优化:

     var el = document.getElementById('mydiv');
     el.style.cssText = 'border-left: 1px; border-right: 2px; padding: 5px;';

上述代码会覆盖已存在的信息,若想保留原来信息,可以把它附加到cssText字符串后面:

    el.style.cssText += '; border-left: 1px;';


另一种一次性修改样式的方法是修改CSS的class名称,而不是改内联样式。可能会带来轻微的性能影响,因为改变类时需要检查级联样式。

    var el = document.getElementById('mydiv');
    el.className = 'active';


缓冲布局信息

尽量减少布局信息的获取次数,获取后把它赋值给局部变量,然后在操作局部变量。

考虑一个例子,把myElement元素沿对角线移动,每次移动一个像素从100PX x 100PX 到 500PX x 500PX。


    // 低效的
    myElement.style.left = 1 + myElement.offsetLeft + 'px';
    myElement.style.top = 1 + myElement.offsetTop + 'px';
    if (myElement.offsetLeft >= 500) {
        stopAnimation();
    }

低效原因:每次元素每次移动是都会查询偏移量,导致浏览器刷新渲染队列而不利于优化。

    current++
    myElement.style.left = current + 'px';
    myElement.style.top = current + 'px';
    if (current >= 500) {

        stopAnimation();
    }


让元素脱离动画流

使用以下步骤可以避免页面中大部分重排:

  1. 使用绝对定位页面上的动画元素,将其脱离文档流
  2. 让元素动起来。
  3. 当动画结束时恢复定位,从而只会下移一次文档的其他元素。


事件委托

根据DOM标准,每个事件都要经历三个阶段:

  • 捕获
  • 达到目的
  • 冒泡

如果你想要拦截所有点击事件,并且阻止其默认行为(打开链接),发送一个Ajax请求来获取内容,然后局部更新页面。用事件委托来实现这个过程,你只需要给所有链接的外层UI“menu”元素添加一个点击监听器,它会捕获并分析点击是否来自连链接。

document.getElementById('menu').onclick = function(e) {


    // 浏览器target
    e = e || window.event;
    var target = e.target || e.srcElement;
   

    var pageid, hrefparts;


    //只关心hrefs,非链接点击退出
    if (target.nodeName !== 'A') {
        return;
    }


    // 从链接中找出页面ID
    hrefparts = target.href.split('/');
    pageid = hrefparts[hrefparts.length - 1];
    pageid = pageid.replace('.html', '');


    // 更新页面
    ajaxRequest('xhr.php?page=' + id, updatePageContents);


    // 浏览器组织默认行为并取消冒泡
    if (typeof e.preventDefault === 'function') {
        e.preventDefault();
        e.stopPropagation();
    } else {
        e.returnValue = false;
        e.cancelBubble = true;
    }
};

跨浏览器兼容的部分包括:

  • 访问事件对象,并判断事件源
  • 取消文档树中的冒泡(可选)
  • 组织默认动作(可选)
1 0
原创粉丝点击