跟踪点击;搜索DOM的性能影响

时间:2011-02-10 17:40:42

标签: javascript dom javascript-events mobile tracking

我有一个javascript插件,可以在DOM中搜索以类名“tracking”开头的任何元素,并将click事件监听器(或其他类型的监听器,如果指定)添加到该元素。这个想法是每次该事件发生在该元素上时,它运行一个javascript函数,将数据发送到我们的流量服务器。这是代码的样子。

// Once the page is completed loaded
window.mmload(function() {      
    // Get the container object
    obj = document.getElementById(name);

    if ( obj.length < 0 )
        throw ("The Id passed into the tracker does not exist ("+name+")");

    // Find all the elements belonging to the tracking class 
    var trackingClass = new RegExp( /tracking\[[a-zA-Z0-9\.\-_]+\]/g );
    var myElements = getElementsByRegex( trackingClass, obj );

    //For each of those elements...
    for( var i in myElements ) {
        var elm = myElements[i];
        var method = elm.className.match( /tracking\[[a-zA-Z0-9\.\-_]+\]/ )[0].split('[')[1].replace(']','').split('.')[2];
        method = typeof( method ) == 'undefined' ? 'click' : method;

        // Add a click event listener
        myElements[i].addEventListener( method, function(e){
            // Get the element, the link (if any), and the args of the event                
            var link = elm.getAttribute('href') == null ? "" : elm.getAttribute('href');
            var args = elm.className.match( /tracking\[[a-zA-Z0-9\.\-_]+\]/ )[0].split('[')[1].replace(']','').split('.');

            // If a link existed, pause it, for now
            if ( link != '' )
                e.preventDefault();

            // Track the event
            eventTracker( args[0], args[1], ( method == 'click' ? 'redirect' : 'default' ), link );

            return false;
        }, true);
    }
});

现在,一旦窗口完全加载,我就会运行这些代码(window.mmload()是我为追加window.onload事件而做的一个函数)。但是,有时我可能需要再次运行此函数,因为我通过带有此类名称的javascript向DOM添加了新元素,我也想跟踪它们。

我的初始解决方案是使用setInterval运行此函数,每隔几毫秒或第二次或任何最有意义的方式检查DOM。但是,我担心如果我采用这种方法可能会减慢网站速度,特别是因为这是在智能手机的移动网站上运行。如果我经常搜索DOM,我不确定我可能会遇到什么样的性能损失。

我想到的另一种方法是在将可追踪元素添加到DOM之后简单地调用该函数。这可能是处理它的最有效方式。然而,我与之合作的人,非常聪明的人,都是网页设计师,他们不经常思考也不能很好地理解代码。所以我可以做得越简单越好。这就是我喜欢setInterval方法的原因,因为它们不需要额外的东西。但如果它明显减慢了网站的速度,我可能不得不采取另一种方法。

3 个答案:

答案 0 :(得分:1)

您应该考虑甚至委派

您只需将一个事件侦听器添加到文档根目录,然后检查事件源自的元素类(event.target)。如果你想包括来自后代的点击,你必须从目标遍历DOM,并检查是否有任何祖先包含该类。

我看到两个主要优点:

  • 它适用于新生成的元素,无需任何额外步骤(因此其他开发人员不必做任何特殊操作)。
  • 它只添加一个事件处理程序,而不是多个,这样可以节省内存。

缺点:

  • 如果在路径中注册了其他事件处理程序,并且它们阻止事件冒泡,则无法注册此事件。

更多信息:

事件处理程序获取event对象作为第一个参数。此对象包含several propertieswhich element the event originated form

E.g。获取目标元素:

var element = event.target || event.srcElement;

这将是一个DOM元素,您可以通过element.className访问这些类。

因此,您的事件监听器可能如下所示(请注意IE uses another method to attach event listeners且事件对象未通过,但可通过window.event获得):

function handler(event) {
    event = event || window.event;
    var target = event.target || event.srcElement;
    if(target.className.match(/tracking\[[a-zA-Z0-9\.\-_]+\]/g) {
        // do your stuff
    }
}

if(document.addEventListener) {
   document.addEventListener('click', handler, false);
}
else {
   document.attachEvent('onclick', handler);
}

但正如我所说,这会错过那些无法冒泡的事件。至少在遵循W3C模型的浏览器中(所以不是IE),您可以通过将最后一个参数设置为true来处理capture phase中的事件:

document.addEventListener('click', handler, true);

答案 1 :(得分:0)

如果您可以在没有IE的情况下生活,那么您可以为窗口/文档/ dom元素挂接change事件。只需在文档级别挂钩,即可在页面中更改某些内容(插入,删除,更改内容)。我相信事件的上下文包含了已经改变的内容,因此找到任何新的可跟踪元素并将间谍代码附加到它上面应该是相当简单的。

答案 2 :(得分:0)

第三种选择是编写一种操作元素的innerHTML的方法。在该方法结束时,只需调用刷新所有内容的函数。

示例:

var setHtml = function(element, newHtml){
     element.innerhtml = newHtml;
     yourRefreshFunction();
}

显然,这需要您的Web开发人员使用此方法来更新dom。而且你必须为任何比简单的html编辑更复杂的事情做这件事。但这给了你这个想法。

希望有所帮助!