天天看點

用new Image().src作LOG統計的一個注意事項 .

用new Image().src作LOG統計的一個注意事項

2009-08-06 17:40

在大型網站做很多使用者行為分析、産品的策劃方案基本上都是通過分析使用者的通路等資訊而做出的,LOG資訊的統計準确性會直接影響到産品的設計開發(比如搜尋結果的先後排名rank值的産生等)。目前最常用的一個寫LOG的方法就是用JavaScript腳本在網頁裡 new Image().src = "http://xxx.com/log?msg="+ msg; 這種統計方法基本上不會幹擾使用者的正常操作,雖然有LOG丢失的可能,但隻要用得好,還是一種非常好的LOG統計回收的方案。

但是這種LOG回收手段有一個非常隐秘的隐患,事情是這樣被發現的。今年3月份百度搜尋結果頁面上線了Suggestion功能更新版,在LOG統計中突然發現上線後的LOG總量比上線前的少了很多(10%以上),表現出來的現象就是LOG丢失了,沒有回收到伺服器中來。

工程師立即做了詳細排除,從各種因素上确定LOG的大量丢失跟網頁上線Suggestion有關,我們馬上對Suggestion腳本進行地毯式排查,逐行分析代碼,結論是這個腳本沒有阻攔 new Image().src 的發包請求(至少表面上是這樣的),這段腳本放在一個腳本閉包中,沒有影響到全局變量/方法,也沒有屏蔽幹擾HTTP請求的因素。

我們又做了一個線下試驗,同樣的代碼環境,線上下的測試環境中用這種 new Image().src 的手段,總共向Server端發送了10000個LOG資料,也沒有發生LOG丢失,試驗的結果也沒有發現LOG丢失的原因。

但是線上上的環境中發生的就是有LOG資料丢失,原因不明,是以隻能緊急下線這個Suggestion更新版。在這個腳本下線之後,LOG統計資料馬上回歸到“原正常”狀态。從這個現象來看,也從另一個角度說明上線的新腳本确實對LOG統計有影響,頭疼呀......

愚者千慮,必有一得!最後方知這個問題的原因是浏覽器的垃圾回收機制!

function c(q) {

    var p=window.document.location.href,sQ='',sV='';

    for(v in q){

        switch (v){

            case "title":sV=encodeURIComponent(q[v].replace(/<[^<>]+>/g,""));break;

            case "url":sV=escape(q[v]);break;

            default:sV=q[v]

        }

        sQ+=v+"="+sV+"&";

    }

    new Image().src = "http://s.baidu.com/w.gif?q=meizz&"+sQ+"path="+p+"&cid=9&t="+ new Date().getTime();

    return true;

}

這個 new Image() 對象沒有賦給任何變量,在這個函數執行結束時,浏覽器的垃圾回收機制對這種“無主”的對象是毫不客氣的回收的,而正是這種回收行為導緻了這個HTTP請求(異步的)沒有發出,進而造成了LOG資料的丢失。那為什麼上線一個腳本就會造成大量的LOG丢失呢?因為一個大腳本的運作回産生大量的“垃圾”,浏覽器垃圾回收也會相應地更頻繁的啟動,進而造成LOG資料丢失。找到原因之後對症下藥,把這個 new Image() 對象賦給一個全局有變量常期持有即可,相應的代碼如下:

var n = "log_"+ (newDate()).getTime();

var c = window[n] =newImage();  //把new Image()賦給一個全局變量長期持有

c.onload = (c.onerror=function(){window[n] = null;});

c = null;      //釋放局部變量c

在這個統計代碼上線之後,百度的搜尋結果頁面的LOG立即多出近10%,之後再上線其它的腳本也沒有再出現LOG統計量的波動。

---------------------------------------------------------------------------------------------------------------------------------

局部變量下,測試連續發1000個log

IE6-7 發現log丢失,某些IE核心浏覽器也發現log丢失

但在FF, chrome下未發現丢失

是以 保險的做法是用一個非局部變量持有

var unique = (function () {  

    var time= (new Date()).getTime()+'-', i=0;  

    return function () {  

       return time + (i++);  

    }  

})();  

var imgLog = function (url) {  

    var data = window['imgLogData'] || (window['imgLogData'] = {});  

    var img = new Image();  

    var uid = unique();  

    img.onload = img.onerror = function () {//銷毀一些對象   

        img.onload = img.onerror = null;  

        img = null;  

        delete data[uid];  

    img.src = url + '&_uid=' + uid;  

};  

本文轉自茄子_2008部落格園部落格,原文連結:http://www.cnblogs.com/xd502djj/p/3291064.html,如需轉載請自行聯系原作者。