從函數劫持角度看開發調試工具AlloyLever

在騰訊的AlloyTeam的Blog上發現了這樣的一款工具:AlloyLever(原blog地址:http://www.alloyteam.com/2016...),以爲很是有趣且實用。尤爲是其實現的原理也並不複雜,卻能夠給日常的調試工做帶來巨大的便利,不得不讓人感嘆凡事就怕認真啊。git

圖片描述

這個就是這款工具的樣子,它整合了web調試中幾個很是頻繁的剛需:看log、看error、看AJAX發包與回包。同時還附有查看timeline、cookie和localStorage的這些功能。雖然這些信息在chrome的調試工具裏面也是觸手可及,但是因爲涉及的緣由,他們被放在跟原web頁面不相關的一個窗口裏,還分了不少的標籤頁,在實際工做中,一個web頁面+F12的調試窗口常常就佔滿了整個屏幕,着實是有些不太方便。這也是這個工具最初被製造出來,想要解決的問題吧。github

這個工具的實現原理,是很簡單的函數劫持。有關於函數劫持的相關知識,可參見這篇文章(https://segmentfault.com/a/11...),其大概原理是建立一個和現有函數同名的函數(固然首先要把原來的函數給保存下來),以覆蓋掉他本來的引用,而後在函數體內先針對參數作一些本身想要實現的功能,最後再調用以前保存的原函數,實現本來的功能。
這個思路也很像redux裏面有關於middleware的設計,只不過redux運用的思想更爲先進,經過一系列結構將各個中間件解耦,互不干擾。而本文的目的不是爲了靈活的使用各類中間件,只是爲了想作一個調試信息的自主整合頁面,因此使用這種強聯繫的耦合方式也沒有什麼大問題。web

原文中的關鍵源碼以下:ajax

window.console = {
    wc: window.console
};    //將本來console的引用指向console的一個成員變量wc,以便在後面擴充的函數中使用。
var self = this;  //保存當前語境中的this
['log', 'error', 'warn', 'debug', 'info'].forEach(function (item) {  //針對console的五種方法
    console[item] = function (msg) {
        this.wc[item](msg);
        self.log(msg, item);
    }
});

代碼選自原網頁,註釋是我加的。chrome

在JavaScript中,函數也是對象的一種,也能像對象同樣擁有本身的變量。因此程序的前三行就是講console這個對象換了一個別名wc保存在console自己內。
第四行是爲了保存當前語境下的this,事實上在瀏覽器的調試工具中直接運行這些代碼的時候,這個this指向的就是全局對象window,因此去掉這一行,將下面的self.log改爲window.log,程序的運行結果是如出一轍的。
保存完了全部須要的變量後,下面的事情就簡單了,遍歷console下的log, error, warn, debug和info這五個方法,把他們都修改爲先執行自己,而後再執行咱們自定義的log方法,在這個自定義的log方法內,咱們能訪問到傳入的參數msg和訪問的原生函數名item,而後就能夠經過這個鉤子,去獲取數據,並作一些處理,顯示到AlloyLever的控制檯上啦。json

而ajax的截獲跟這個原理也差很少,代碼以下:redux

var XHR = window.XMLHttpRequest;
 
window.XMLHttpRequest=function(){
    var xhr = new XHR();
    checkSuccess(xhr);
    return xhr;
};
 
window.XMLHttpRequest.realXHR = XHR;
 
var self=this;
 
function checkSuccess(xhr) {
    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
        self.option.xhrs.push({url:xhr.responseURL, json:JSON.stringify(JSON.parse( xhr.responseText), null, "\t")})
    }else if(xhr.status>=400) {
        console.error(xhr.responseURL +' '+xhr.status+' ('+xhr.statusText+')')
    }
    else{
        window.setTimeout(function () {
            checkSuccess(xhr);
        }, 0);
    }
}

區別就是由於ajax是異步請求,因此在函數內部內置了一個setTimeout循環,若是請求未完成則一直循環,直到請求完成,內容被捕獲爲止。segmentfault

這個工具還有個移動端的版本:https://github.com/WechatFE/v...
對於作微信開發的小夥伴們,之後的測試就方便多啦!瀏覽器

相關文章
相關標籤/搜索