关于vConsole 源码的理解分享(vConsole一个移动端调试控制台工具)(2)

2023-12-20 01:58

本文主要是介绍关于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 functionsXMLReq._requestID = id;XMLReq._method = method;XMLReq._url = url;//  模拟XMLHttpRequest的onreadystatechangelet _onreadystatechange = XMLReq.onreadystatechange || function() {};let onreadystatechange = function() {let item = that.reqList[id] || {};// update statusitem.readyState = XMLReq.readyState;item.status = 0;if (XMLReq.readyState > 1) {item.status = XMLReq.status;}item.responseType = XMLReq.responseType;if (XMLReq.readyState == 0) {// UNSENTif (!item.startTime) {item.startTime = (+new Date());}} else if (XMLReq.readyState == 1) {// OPENEDif (!item.startTime) {item.startTime = (+new Date());}} else if (XMLReq.readyState == 2) {// HEADERS_RECEIVEDitem.header = {};let header = XMLReq.getAllResponseHeaders() || '',headerArr = header.split("\n");// extract plain text to key-value formatfor (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) {// DONEclearInterval(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);};//覆盖原始默认的onreadystatechangeXMLReq.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 dataif (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)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/514447

相关文章

深入理解Mysql OnlineDDL的算法

《深入理解MysqlOnlineDDL的算法》本文主要介绍了讲解MysqlOnlineDDL的算法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小... 目录一、Online DDL 是什么?二、Online DDL 的三种主要算法2.1COPY(复制法)

基于Python开发Windows自动更新控制工具

《基于Python开发Windows自动更新控制工具》在当今数字化时代,操作系统更新已成为计算机维护的重要组成部分,本文介绍一款基于Python和PyQt5的Windows自动更新控制工具,有需要的可... 目录设计原理与技术实现系统架构概述数学建模工具界面完整代码实现技术深度分析多层级控制理论服务层控制注

Java服务实现开启Debug远程调试

《Java服务实现开启Debug远程调试》文章介绍如何通过JVM参数开启Java服务远程调试,便于在线上排查问题,在IDEA中配置客户端连接,实现无需频繁部署的调试,提升效率... 目录一、背景二、相关图示说明三、具体操作步骤1、服务端配置2、客户端配置总结一、背景日常项目中,通常我们的代码都是部署到远程

基于Go语言开发一个 IP 归属地查询接口工具

《基于Go语言开发一个IP归属地查询接口工具》在日常开发中,IP地址归属地查询是一个常见需求,本文将带大家使用Go语言快速开发一个IP归属地查询接口服务,有需要的小伙伴可以了解下... 目录功能目标技术栈项目结构核心代码(main.go)使用方法扩展功能总结在日常开发中,IP 地址归属地查询是一个常见需求:

使用python制作一款文件粉碎工具

《使用python制作一款文件粉碎工具》这篇文章主要为大家详细介绍了如何使用python制作一款文件粉碎工具,能够有效粉碎密码文件和机密Excel表格等,感兴趣的小伙伴可以了解一下... 文件粉碎工具:适用于粉碎密码文件和机密的escel表格等等,主要作用就是防止 别人用数据恢复大师把你刚删除的机密的文件恢

java 恺撒加密/解密实现原理(附带源码)

《java恺撒加密/解密实现原理(附带源码)》本文介绍Java实现恺撒加密与解密,通过固定位移量对字母进行循环替换,保留大小写及非字母字符,由于其实现简单、易于理解,恺撒加密常被用作学习加密算法的入... 目录Java 恺撒加密/解密实现1. 项目背景与介绍2. 相关知识2.1 恺撒加密算法原理2.2 Ja

Nginx屏蔽服务器名称与版本信息方式(源码级修改)

《Nginx屏蔽服务器名称与版本信息方式(源码级修改)》本文详解如何通过源码修改Nginx1.25.4,移除Server响应头中的服务类型和版本信息,以增强安全性,需重新配置、编译、安装,升级时需重复... 目录一、背景与目的二、适用版本三、操作步骤修改源码文件四、后续操作提示五、注意事项六、总结一、背景与

Android实现图片浏览功能的示例详解(附带源码)

《Android实现图片浏览功能的示例详解(附带源码)》在许多应用中,都需要展示图片并支持用户进行浏览,本文主要为大家介绍了如何通过Android实现图片浏览功能,感兴趣的小伙伴可以跟随小编一起学习一... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

JavaScript中的高级调试方法全攻略指南

《JavaScript中的高级调试方法全攻略指南》什么是高级JavaScript调试技巧,它比console.log有何优势,如何使用断点调试定位问题,通过本文,我们将深入解答这些问题,带您从理论到实... 目录观点与案例结合观点1观点2观点3观点4观点5高级调试技巧详解实战案例断点调试:定位变量错误性能分

Python实战之SEO优化自动化工具开发指南

《Python实战之SEO优化自动化工具开发指南》在数字化营销时代,搜索引擎优化(SEO)已成为网站获取流量的重要手段,本文将带您使用Python开发一套完整的SEO自动化工具,需要的可以了解下... 目录前言项目概述技术栈选择核心模块实现1. 关键词研究模块2. 网站技术seo检测模块3. 内容优化分析模