1. 程式人生 > >關於vConsole 原始碼的理解分享(vConsole一個移動端除錯控制檯工具)(2)

關於vConsole 原始碼的理解分享(vConsole一個移動端除錯控制檯工具)(2)

終於可來搞一搞日誌模組的原始碼了,其實程式碼都很簡單(哈哈哈),我開了一下git的日誌,想來我們現在看到的程式碼,都是之前迭代的程式碼,不是一開始,一個函式就很多行程式碼的,所以要理清條路,理解為什麼這樣加程式碼,當然能一開始就分清楚函式定義多少個,後面好加程式碼,擴充套件的 這個思路架構也是我們要瞻仰,學習的。
log這個模組的類圖結構知道,它在VConsolePlugin上又封裝了一層,類圖結構件上一篇文章上一篇文章
即VConsoleLogTab 作為一個log模組基礎的類結構
廢話不多說直接貼程式碼看實現,程式碼才是王道

什麼建構函式和初始化就不說了,直接來看怎麼替代js瀏覽器物件的列印

/**
     * replace window.console with vConsole method
     * @private
     */
    mockConsole() {
        const that = this;
        const methodList = ['log', 'info', 'warn', 'debug', 'error'];
        if (!window.console) {
            window.console = {};
        } else {
            methodList.map(function
(method) { that.console[method] = window.console[method]; }); that.console.time = window.console.time; that.console.timeEnd = window.console.timeEnd; that.console.clear = window.console.clear; } methodList.map(method =>
{ window.console[method] = (...args) => { this.printLog({ logType: method, logs: args }); }; }); const timeLog = {} window.console.time = function(label) { timeLog[label] = Date.now(); }; window.console.timeEnd = function(label) { var pre = timeLog[label]; if (pre) { console.log(label + ':', (Date.now() - pre) + 'ms'); delete timeLog[label]; } else { console.log(label + ': 0ms'); } }; window.console.clear = (...args) => { that.clearLog(); that.console.clear.apply(window.console, args); }; }

該方法就是模擬console物件

  • 判斷window的console物件是否存在
  • 如果不存在就讓console = {},for迴圈自己實現,console的erron,log等方法,
  • 如果存在,劫持console.log的各個方法,將方法儲存在that物件中,其實我也不知道這個是個什麼意思,我覺得這個劫持可以不要,反正你後面都是全部自己實現了log,error,warn,clear,time,timeEnd,等方法,不知道作者這裡是個什麼意思

這樣差不多log模組畢,接下來看看network,這裡就不賣關子了,其實網路請求也是通過類似於日誌模組模擬ajax的方式。

在此之前,來梳理下window.XMLHttpRequest物件的網路請求流程

  1. 在後臺與伺服器交換資料,就會用到XMLHttpRequest物件
  2. 網路請求發生時,先回建立XMLHttpRequest物件即readyState = 0 也是呼叫open()方法
  3. 緊接著XMLHttpRequest物件呼叫send()方法,傳送客戶端網路請求,等待伺服器返回,即readyState的值為1 ,2,3的變化中(其中何時變化為何值可以參考下https://www.cnblogs.com/liujiale/p/5388110.html
  4. 再次XMLHttpRequest等待伺服器響應完畢,readyState為4
    注意這個onreadystatechange這個事件很重要,每當readyState值變化是都會觸發這個方法,在這個方法我們就可以取用XMLHttpRequest物件的一些有用的屬性值來做文章了比如responseText,status等
    所以瞭解了這個過程,在來看下面的程式碼就很簡單,說白了就是重寫了send,open,onreadystatechange等方法
  /**
     * mock ajax request
     * @private
     */
    mockAjax() {
        let _XMLHttpRequest = window.XMLHttpRequest;
        if (!_XMLHttpRequest) { return; }
        //將this儲存起來
        let that = this;
        let _open = window.XMLHttpRequest.prototype.open,
            _send = window.XMLHttpRequest.prototype.send;
        that._open = _open;
        that._send = _send;

        // 模擬XMLHttpRequest的open方法
        window.XMLHttpRequest.prototype.open = function() {
            let XMLReq = this;
            //分割請求的引數
            let args = [].slice.call(arguments),
                method = args[0],
                url = args[1],
                id = that.getUniqueID(); //設定一個值儲存當前請求的唯一id,唯一標識
            //定義一個時間計時器
            let timer = null;

            // may be used by other functions
            XMLReq._requestID = id;
            XMLReq._method = method;
            XMLReq._url = url;

            //  模擬XMLHttpRequest的onreadystatechange
            let _onreadystatechange = XMLReq.onreadystatechange || function() {};
            let onreadystatechange = function() {
                let item = that.reqList[id] || {};
                // update status
                item.readyState = XMLReq.readyState;
                item.status = 0;
                if (XMLReq.readyState > 1) {
                    item.status = XMLReq.status;
                }
                item.responseType = XMLReq.responseType;

                if (XMLReq.readyState == 0) {
                    // UNSENT
                    if (!item.startTime) {
                        item.startTime = (+new Date());
                    }
                } else if (XMLReq.readyState == 1) {
                    // OPENED
                    if (!item.startTime) {
                        item.startTime = (+new Date());
                    }
                } else if (XMLReq.readyState == 2) {
                    // HEADERS_RECEIVED
                    item.header = {};
                    let header = XMLReq.getAllResponseHeaders() || '',
                        headerArr = header.split("\n");
                    // extract plain text to key-value format
                    for (let i = 0; i < headerArr.length; i++) {
                        let line = headerArr[i];
                        if (!line) { continue; }
                        let arr = line.split(': ');
                        let key = arr[0],
                            value = arr.slice(1).join(': ');
                        item.header[key] = value;
                    }
                } else if (XMLReq.readyState == 3) {
                    // LOADING
                } else if (XMLReq.readyState == 4) {
                    // DONE
                    clearInterval(timer);
                    item.endTime = +new Date(),
                        item.costTime = item.endTime - (item.startTime || item.endTime);
                    item.response = XMLReq.response;
                } else {
                    clearInterval(timer);
                }

                if (!XMLReq._noVConsole) {
                    that.updateRequest(id, item);
                }
                return _onreadystatechange.apply(XMLReq, arguments);
            };
            //覆蓋原始預設的onreadystatechange
            XMLReq.onreadystatechange = onreadystatechange;
            //為了怕請求過程佔用第三方應用匯修改xhr預設的方法,所以用了一個定時器迴圈來監聽readyState的變化
            let preState = -1;
            timer = setInterval(function() {
                if (preState != XMLReq.readyState) {
                    preState = XMLReq.readyState;
                    onreadystatechange.call(XMLReq);
                }
            }, 10);

            return _open.apply(XMLReq, args);
        };

        // 預設send方法
        window.XMLHttpRequest.prototype.send = function() {
            let XMLReq = this;
            let args = [].slice.call(arguments),
                data = args[0];
            //重請求池找出相應的請求
            let item = that.reqList[XMLReq._requestID] || {};
            item.method = XMLReq._method.toUpperCase();
            //處理url後面跟著的引數,
            //1,先以?分割為陣列
            let query = XMLReq._url.split('?'); // a.php?b=c&d=?e => ['a.php', 'b=c&d=', '?e']
            // 2,在去除最前面的陣列
            item.url = query.shift(); // => ['b=c&d=', '?e']
            if (query.length > 0) {
                item.getData = {};
                //3,然後剩下的?又重新連線在一起
                query = query.join('?'); // => 'b=c&d=?e'
                //4,在以& 去鍵值對
                query = query.split('&'); // => ['b=c', 'd=?e']
                for (let q of query) {
                    q = q.split('=');
                    item.getData[q[0]] = q[1];
                }
            }
            //處理post請求方式,注意這裡 會有url接引數,但又是post請求的情況,這裡也能處理
            if (item.method == 'POST') {
                // save POST data
                if (tool.isString(data)) {
                    let arr = data.split('&');
                    item.postData = {};
                    for (let q of arr) {
                        q = q.split('=');
                        item.postData[q[0]] = q[1];
                    }
                } else if (tool.isPlainObject(data)) {
                    item.postData = data;
                }

            }

            if (!XMLReq._noVConsole) {
                that.updateRequest(XMLReq._requestID, item);
            }

            return _send.apply(XMLReq, args);
        };

    };

這個就比較底層了,其實也不是,只不過我們平時開發的時候,習慣用封裝好的比如jq等,其實背後做了很多時候事情!

接下來是最後的儲存模組,VConsole裡主要是列了cookie和localStorage的儲存
localStorage就不說了,貼心cookie的的程式碼


  getCookieList() {
    if (!document.cookie || !navigator.cookieEnabled) {
      return [];
    }

    let list = [];
    let items = document.cookie.split(';');
    for (let i=0; i<items.length; i++) {
      let item = items[i].split('=');
      let name = item.shift().replace(/^ /, ''),
          value = item.join('=');
      list.push({
        name: decodeURIComponent(name),
        value: decodeURIComponent(value)
      });
    }
    return list;
  }

結束了,以上是個人見解,歡迎指正批評!謝謝

相關推薦

關於vConsole 原始碼理解分享vConsole一個移動除錯控制檯工具(2)

終於可來搞一搞日誌模組的原始碼了,其實程式碼都很簡單(哈哈哈),我開了一下git的日誌,想來我們現在看到的程式碼,都是之前迭代的程式碼,不是一開始,一個函式就很多行程式碼的,所以要理清條路,理解為什麼這樣加程式碼,當然能一開始就分清楚函式定義多少個,後面好加程式

vue中使用vconsole--移動除錯神器

Vue中使用vconsole除錯手機移動端的點選事件 先使用npm install vconsole下載安裝依賴包 在Vue專案中新建 vconsole.js 檔案 ,在檔案中寫入 import Vconsole from 'vconsole' const vConsole = ne

vue---移動除錯功能vConsole

一. 簡述 web端專案可以檢視瀏覽器控制檯資訊,方便除錯。然而移動端專案沒有控制檯可看,除錯起來特困難。最近在做基於vue框架的移動端專案,有的bug不看日誌,無法除錯,很頭疼。百度一下終於解決了這個難題,基於vue的有個可以在移動端檢視日誌的外掛vConsole,很好用

移動除錯---vconsole

官方地址:https://www.npmjs.com/package/vconsole 使用方法: 1  本地呼叫  下載vconsole   npm install vconsole  在專案中引入  

h5移動除錯工具vConsole

1.npm使用方法 npm 安裝vconsole npm install vconsole -D 在 main.js 中引用 import Vconsole from 'vconsole'; const vConsole = new

移動除錯工具--vConsole

Github地址:https://github.com/Tencent/vConsole平時Web端除錯時,我們一般習慣用console來讓控制檯輸出資訊,但是在移動端,我們無法再用console來觀察控制檯輸出的資訊,可以用alert代替console.log,但是aler

.NET Core 3.0之深入原始碼理解ObjectPool

寫在前面 物件池是一種比較常用的提高系統性能的軟體設計模式,它維護了一系列相關物件列表的容器物件,這些物件可以隨時重複使用,物件池節省了頻繁建立物件的開銷。 它使用取用/歸還-重複取用的操作模式,如下圖所示: 本文將主要介紹物件池的基本概念、物件池的優勢及其工作機制,下一篇文件將從原始碼角度介紹.NET

.NET Core 3.0之深入原始碼理解ObjectPool

寫在前面 前文主要介紹了ObjectPool的一些理論基礎,本文主要從原始碼角度理解Microsoft.Extensions.ObjectPool是如何實現的。下圖為其三大核心元件圖: 核心元件 ObjectPool ObjectPool是一個泛型抽象類,裡面只有兩個抽象方法,Get和Return。它從底

.NET Core 3.0之深入原始碼理解HealthCheck

寫在前面 我們的系統可能因為正在部署、服務異常終止或者其他問題導致系統處於非健康狀態,這個時候我們需要知道系統的健康狀況,而健康檢查可以幫助我們快速確定系統是否處於正常狀態。一般情況下,我們會提供公開的HTTP介面,用於專門化健康檢查。 NET Core提供的健康檢查庫包括Microsoft.Extensio

.NET Core 3.1之深入原始碼理解HealthCheck

寫在前面前文討論了HealthCheck的理論部分,本文將討論有關HealthCheck的應用內容。可以監視記憶體、磁碟和其他物理伺服器資源的使用情況來了解是否處於正常狀態。執行狀況檢查可以測試應用的依賴項(如資料庫和外部服務終結點)以確認是否可用和正常工作。執行狀況探測可以由容器業務流程協調程式和負載均衡器

控制容器文字行數pc和 移動

phone 行數 spa pre size 以及 :hover 框架 mx4 寫在前面的話:   對於文字的單行以及多行顯示,應該是經常用到的一個功能了,看下文吧~ pc 端:   1. 單行限制(兼容所有瀏覽器) 這裏加了一個 鼠標移入時顯示全部 的效果:

各主流瀏覽器PC、移動userAgent屬性信息

ble 信息 ie 8 瀏覽器版本 實用 link row inux oppo PC: IE、QQ、chrome、firefox、360、safair 移動端:微信內置瀏覽器、QQ、獵豹、百度、UC、2345、系統自帶 PC:   ie:       Mozilla/5

學習資料分享Java第一行代碼視頻<susmote.com>

pos medium 面向 學習 資料 java培訓 href 網盤 高級 17年買了一本書,第一行代碼(JAVA),李興華編寫的。 一開始我是按照書本一頁一頁的啃,一個點一個點的去學,雖然當時學的有些枯燥,但裏面的知識點大部分還是弄的懂,只是一次偶然,因為有點質疑書上寫

JS - 各瀏覽器對ES2015/ES6的支援情況桌面移動、以及伺服器

2015年6月, ES2015(即 ECMAScript 6、ES6) 正式釋出。ES2015 是該語言的一個顯著更新,也是自 2009年 ES5 標準確定後的第一個重大更新。 ES6 提供了許多新特性,但並不是所有的瀏覽器都能夠完美支

eruda.js 移動除錯神器使用教程eruda

在日常的移動端開發時,一般都是試用chrome瀏覽器的移動端模式進行開發和除錯,只有在chrome除錯完成,沒有問題了才會上到真機測試,移動端開發的一大問題就在於此, 各種品牌各種型號手機,手機中各種型別的瀏覽器APP........還好移動端的相對一致點,但是往往都會有一些各種各

Redis基本使用及百億數據量中的使用技巧分享附視頻地址及觀看指南

轉換 拆分 cache 避免 new 解決方案 pipe 收回 實例部署 作者:依樂祝原文地址:https://www.cnblogs.com/yilezhu/p/9941208.html 主講人:大石頭 時間:2018-11-10 晚上20:00 地

深入理解jvm二、常用的垃圾收集器

1.Serial 單執行緒收集器,它在進行垃圾收集時必須暫停其他工作執行緒,直到收集結束。是虛擬機器執行在客戶端下的預設新生代收集器。 相對於其他收集器的單執行緒來說,簡單高效。 2.ParNew 相當於Serial收集器的多執行緒版本,一般是執行在服務端的虛擬機器首選的新生代收集器

深入理解jvm三、常用的垃圾收集規則

1.物件優先在Eden分配 Eden Space字面意思是伊甸園,物件被建立的時候首先放到這個區域,進行垃圾回收後,不能被回收的物件被放入到空的survivor區域。 Survivor Space倖存者區,用於儲存在eden space記憶體區域中經過垃圾回收後沒有被回收的物件。Surviv

利用js自動檢測pc移動,js程式碼,需要寫兩個網頁,一個pc,一個移動

假設pc/index.html是pc端的網頁,mobile/index.html是移動端的網頁 在外部設定一個html進行判斷,分別跳轉; //判斷如果是pc端,自動跳到pc/index.html //安卓手機自動跳到mobile/

java使用itext操作填充pdf模板,根據一個模板生成多頁資料

直接開始需要兩個jar包 itext-asian-5.2.0.jar和 itextpdf-5.5.6.jar ,我的業務邏輯可能比較複雜,在這裡我就簡單的提供一個demo ,需要的人自己按照自己的業務邏輯來改。 首先我們要用 Adobe Acrobat 來編輯p