关于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

相关文章

Java 正则表达式URL 匹配与源码全解析

《Java正则表达式URL匹配与源码全解析》在Web应用开发中,我们经常需要对URL进行格式验证,今天我们结合Java的Pattern和Matcher类,深入理解正则表达式在实际应用中... 目录1.正则表达式分解:2. 添加域名匹配 (2)3. 添加路径和查询参数匹配 (3) 4. 最终优化版本5.设计思

基于Java实现回调监听工具类

《基于Java实现回调监听工具类》这篇文章主要为大家详细介绍了如何基于Java实现一个回调监听工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录监听接口类 Listenable实际用法打印结果首先,会用到 函数式接口 Consumer, 通过这个可以解耦回调方法,下面先写一个

使用Python构建一个Hexo博客发布工具

《使用Python构建一个Hexo博客发布工具》虽然Hexo的命令行工具非常强大,但对于日常的博客撰写和发布过程,我总觉得缺少一个直观的图形界面来简化操作,下面我们就来看看如何使用Python构建一个... 目录引言Hexo博客系统简介设计需求技术选择代码实现主框架界面设计核心功能实现1. 发布文章2. 加

JS+HTML实现在线图片水印添加工具

《JS+HTML实现在线图片水印添加工具》在社交媒体和内容创作日益频繁的今天,如何保护原创内容、展示品牌身份成了一个不得不面对的问题,本文将实现一个完全基于HTML+CSS构建的现代化图片水印在线工具... 目录概述功能亮点使用方法技术解析延伸思考运行效果项目源码下载总结概述在社交媒体和内容创作日益频繁的

深入理解Apache Kafka(分布式流处理平台)

《深入理解ApacheKafka(分布式流处理平台)》ApacheKafka作为现代分布式系统中的核心中间件,为构建高吞吐量、低延迟的数据管道提供了强大支持,本文将深入探讨Kafka的核心概念、架构... 目录引言一、Apache Kafka概述1.1 什么是Kafka?1.2 Kafka的核心概念二、Ka

基于Python打造一个全能文本处理工具

《基于Python打造一个全能文本处理工具》:本文主要介绍一个基于Python+Tkinter开发的全功能本地化文本处理工具,它不仅具备基础的格式转换功能,更集成了中文特色处理等实用功能,有需要的... 目录1. 概述:当文本处理遇上python图形界面2. 功能全景图:六大核心模块解析3.运行效果4. 相

springboot项目中常用的工具类和api详解

《springboot项目中常用的工具类和api详解》在SpringBoot项目中,开发者通常会依赖一些工具类和API来简化开发、提高效率,以下是一些常用的工具类及其典型应用场景,涵盖Spring原生... 目录1. Spring Framework 自带工具类(1) StringUtils(2) Coll

基于Python实现高效PPT转图片工具

《基于Python实现高效PPT转图片工具》在日常工作中,PPT是我们常用的演示工具,但有时候我们需要将PPT的内容提取为图片格式以便于展示或保存,所以本文将用Python实现PPT转PNG工具,希望... 目录1. 概述2. 功能使用2.1 安装依赖2.2 使用步骤2.3 代码实现2.4 GUI界面3.效

基于Python和MoviePy实现照片管理和视频合成工具

《基于Python和MoviePy实现照片管理和视频合成工具》在这篇博客中,我们将详细剖析一个基于Python的图形界面应用程序,该程序使用wxPython构建用户界面,并结合MoviePy、Pill... 目录引言项目概述代码结构分析1. 导入和依赖2. 主类:PhotoManager初始化方法:__in

Python通过模块化开发优化代码的技巧分享

《Python通过模块化开发优化代码的技巧分享》模块化开发就是把代码拆成一个个“零件”,该封装封装,该拆分拆分,下面小编就来和大家简单聊聊python如何用模块化开发进行代码优化吧... 目录什么是模块化开发如何拆分代码改进版:拆分成模块让模块更强大:使用 __init__.py你一定会遇到的问题模www.