小程序调试技术导读

近期团队内在自研小程序,我负责开发者工具中的调试部分。调试作为面向开发者的基础能力,扮演了极为重要的角色。

本篇文章是导读文章。

调试能力从0到1一共经历了4个版本,接下来的文章将会以这4个版本为主线分别进行介绍。

初始版

初始版通信关系图
上图为调试还不存在时的一个通信关系图。

在彼时已经实现了逻辑代码与渲染代码的运行隔离,其中逻辑代码是运行在一个vm中的。

  1. 渲染层通过Electron提供的IPC能力与electron进行通信。
  2. electron持有vm的引用,在收到渲染层的请求后,Electron会直接交给vm执行。
  3. vm中运行的代码会通过vm的Context方法将执行结果抛出。
  4. vm收到代码后直接通过渲染层容器BrowserView的引用通过executeJavaScript将结果返还给渲染层。

通过以上4步完成了一个简单的渲染层、逻辑层的通信闭环。这其中有渲染层代码、逻辑层代码、preload、electron、vm、BrowserView 6个角色参与。

这个阶段的特点是:实现了渲染代码与逻辑代码的隔离,还不具备基础的断点调试能力。

第一版

image
这一版比初始版要复杂了一些,它实现了逻辑代码的断点能力。它的主要改进是:

  1. 将vm转移到了独立的进程中。
  2. 通过node --inspect-brk使逻辑层代码运行于调试状态。
  3. 由于逻辑层代码运行于独立进程中,所以使用了IPC使渲染层与逻辑层维持通信状态。
  4. 加入了可视化的调试界面。可以对代码执行基本的调试控制操作,可以从控制台看到渲染层的日志输出。

它的不足之处在于无法审查DOM结构,也无法查看Network记录。

第二版

image

这一版比上一版的改进在于可以查看Network记录,同时也可以审查基本的DOM结构。

运行示例:image

这一版将逻辑层代码运行于worker内。调试审查面板采用了electron自带的调试工具。

在worker内部运行逻辑代码解决了Network审查的问题。electron自带的调试工具可以以较小的成本在调试工具中增加一个Tab,这里用了chrome extensions的能力。

为了不影响逻辑代码的执行,这一版采用adapter扮演了上一版vm的角色,使上层的逻辑代码无感知的进行了运行时环境的迁移,adapter负责底层数据的通信。

这一版最大的难点在DOM结构的审查。这是因chrome extensions 运行于逻辑层容器上,而DOM信息位于渲染层容器上。有人可能会问,把扩展放到渲染层容器上不就解决了吗?答案是否定的,因为console network source 这些能力与逻辑层严格关联。而调试面板只有一个,必须做出成本方面的取舍。

解决DOM审查的办法是将渲染层与逻辑层的审查通信通道打通。这里就不得不提到chrome extensions的实现,chrome extensions主要由3部分组成:

  • frontend.js 这个文件运行于调试面板tab内。
  • backend.js 这个文件运行于网页的上下文中。
  • background.js 这个文件负责frontend.js与backend.js的通信。

以下这张图简单的描述了它们三者之间的关系:
image

这里以已经非常成熟的extensions vue-devtools来做说明。vue-devtools的结构和上图一样,backend.js是负责从页面中获得Vue的组件树结构然后再通过background.js发送给frontend.js来展示的。

而在我们的小程序中,backend.js所运行的环境中并没有Vue的组件信息,这些信息在哪呢?它位于渲染层的运行环境中。所以我们需要做一些适当的改造(基于vue-devtools),如下:
image
就是将原本运行于逻辑层网页环境中的backend.js移植到了渲染层网页环境中执行。而之前在逻辑层网页环境中运行的backend.js变为了backend.proxy.js,它负责内外环境的通信。这里的内是指extensions的proxy.js,外是指electron.js。渲染层中的GlueLayout.js扮演了之前的proxy.js的角色,负责backend.js与外部的通信适配。

以上仅仅是打通了逻辑层与渲染层的审查通信通道,而这还不够。因为我们需要审查的是渲染层的DOM结构,目前只能看到的是渲染层的Vue组件结构。所以还需要一些改造。

为了兼容DOM审查与数据审查两种能力,我们想出了一种创新方式,就是将组件结构与DOM结构合二为一。例如:

# Main.vue
<template><div class="main"><Hello></Hello></div>
</template>
# Hello.vue
<template><div class="hello"><span>This is Hello components!</span></div>
</template>

实际审查时会变为:

<div class="main"><Hello><div class="hello"><span>This is Hello components!</span></div></Hello>
</div>

当点击组件节点时展示的是组件本身的信息(完全是vue-devtools的能力),而当点击DOM节点时展示的是元素本身的信息(没有实现)。

这一版相比上一版实现了DOM树结构的审查与组件数据审查,也实现了Network的审查。而不足之处在于还不能够实现Elements本身的审查,比如修改样式,查看内外边距等基础能力。

第三版

image
这一版相比于上一版有了比较完善的能力:

  • 完整的DOM审查能力。
  • Console控制台。
  • Source调试。
  • Network审查。
  • 页面数据审查。

与市面上的其它小程序开发者工具相比,该有的基础能力都具备了。

这一版的调试面板又采用了第二版所使用的chrome devtools frontend方案。与第二版不同的在于逻辑代码的运行采用的是第三版的方案。

这一版遇到了三个很大的挑战:

  1. 如何使用一个调试面板控制渲染层的DOM结构与逻辑层的代码逻辑?
  2. 如何在缺少资料的情况下在chrome devtools frontend项目中增加一个新的有完全能力的tab?
  3. 如何获得审查数据?

这里简单分别说明一下以上三个问题是如何解决的。

问题1

chrome devtools frontend(下文简称frontend)是谷歌官方研发的给chrome使用的调试面板项目。

frontend在启动后会通过WebSocket连接到一个目标调试地址,注意,**这个地址只能是一个地址。**那么问题来了,现在逻辑层、渲染层分别运行于两个独立的环境中,我应该连接谁呢?连接谁都不靠谱。

唯一的解决方案是,我们提供一个调试中继服务,让frontend连接这个中继服务,这个中继服务分别去连接逻辑层调试服务与渲染层调试服务。如下图所示:
image

问题2

由于frontend项目在今年完全改为了TS的写法,导致每次修改、查看需要花费10多分钟的编译时间。而为了压缩这可观的时间,顺藤摸瓜找到了在修改为TS写法之前的最后一个版本,这个版本是用JS写的,可以修改后直接在浏览器中预览效果。最大的好处在于可以实时的调试代码了,这对了解frontend项目的运行原理大开方便之门。

有了以上条件还不够,因为frontend项目不同于传统的前端项目,它没有构建的过程,庞大的项目全是依靠配置文件动态加载生成的。

经过一段时间的摸索和大量的调试,找到了frontend从启动到最终渲染一个TAB的完整过程。知道了它是怎么加载的,那增加一个TAB也是板上钉钉的事情了。

在frontend中增加一个TAB的关键代码一览:

image

但问题到此就解决了?不不不,还早着呢。完成以上步骤仅仅是有了一个TAB,但它里面是空的,什么都没有,那怎么往里面添加内容呢?

下面这段代码是调试面板Element的初始化代码(一部分):

image

Emmm,怎么说呢,和我们一般见到的形式完全不同,既不是原生DOM操作,也不是JQuery、Vue这类的第三方框架,这怎么下手呢?

原来frontend封装了大量的组件,上面代码中的ElementPanel所继承的UI.Panel.Panel就是一个组件。最开始我尝试使用这些组件,但由于没有文档,加上代码量庞大,用起来非常的吃力,效果也不好。最终通过代码阅读找到了这些组件暴露在外的element,那么我将Vue挂载到这个Element上就可以使用vue的方式去实现这个TAB的内容了。如图所示:

image

问题3

因为frontend是基于websocket与外界通信的,element、console、source这些模块都是通过内置的websocket client与外界交换数据。而这个websocket实例被高度封装,很难在Vue中直接使用。例如,Element是通过这种方式去获取DOM数据的:
image

注意这里的invoke_getDocument方法是动态合成的:
image

这里不展开展示细节了。总之如果按照frontend的方式实现通信的过程改造难度非常大。这时我想另辟蹊径,自建一条通信通道。但后来想想又放弃了,这不是个好的办法。最终还是决定从内置的websocket上入手,看看哪些关键的地方可以暴露给全局使用。最终经过不断的调试找到了这个关键的对象:
image

这样一来,我便可以随便使用了:

export function sendMessage(method, params) {return new Promise((resolve, reject) => {// self.target为通信关键对象self.target._router.sendMessage("", "DataInspect", `DataInspect.${method}`, params, (error, result) => {if (error) {console.error('Request ' + method + ' failed. ' + JSON.stringify(error));reject(null);return;}resolve(result);})})
}

target这个对象可以保证请求与回调完全一一对应,不出错,不混,不乱。这为我后来实现主动监听逻辑层回调提供了实现思路。

Final

*小程序的调试技术从0到1一共经历了3个版本的演化才达到了一个完善的状态,虽然演化的过程中被不断推翻之前的方案,但带来的结果终究是完美的。这是一个必然的过程,因为不踩坑不知道坑的存在。

小程序调试这块对我来说最大的挑战在于:每一步几乎都在摸索。假设、实现、验证无限循环,不断完善。实际上调试涉及的最核心的技术应该是通信:比如逻辑层与渲染层的通信、调试面板与调试源的通信,经历了各种复杂的角色才完成了一项基础能力。


最后贴一下第三版基本调试能力实现全图:

数据审查面板:
image

Source面板:
image

Console控制台:
image

DOM审查面板:
image

调试中断:
image

Network网络资源审查:
image

Network XHR审查:
image

好,导读文章就到这里。接下来会分几篇文章详细介绍第三版的完整实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/478598.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

可交互的 Attention 可视化工具!我的Transformer可解释性有救了?

文 | Sherry视觉是人和动物最重要的感觉&#xff0c;至少有80%以上的外界信息是经过视觉获得的。我们看论文的时候&#xff0c;通过图表来确定文章的大致内容往往也是一个更高效的 说到深度神经网络的可视化&#xff0c;最经典的莫过于的CNN密恐图了&#xff1a;这种可视化方法…

ImportError: libSM.so.6: cannot open shared object file: No such file or dir

ImportError: libSM.so.6: cannot open shared object file: No such file or dir 出现错误&#xff1a; ImportError: libSM.so.6: cannot open shared object file: No such file or dir 解决方法&#xff1a; apt-get install libsm6如果你出现了上面的错误&#xff0c;那…

LeetCode 347. 前 K 个高频元素(哈希/优先队列)

文章目录1. 题目2. 解题2.1 哈希2.2 优先队列1. 题目 给定一个非空的整数数组&#xff0c;返回其中出现频率前 k 高的元素。 示例 1: 输入: nums [1,1,1,2,2,3], k 2 输出: [1,2]示例 2: 输入: nums [1], k 1 输出: [1] 说明&#xff1a; 你可以假设给定的 k 总是合理的&…

Lego-美团接口自动化测试实践

一、概述 1.1 接口自动化概述 众所周知&#xff0c;接口自动化测试有着如下特点&#xff1a; 低投入&#xff0c;高产出。比较容易实现自动化。和UI自动化测试相比更加稳定。如何做好一个接口自动化测试项目呢&#xff1f; 我认为&#xff0c;一个“好的”自动化测试项目&#…

小程序调试技术详解(基于小猴小程序)

本篇文章主要围绕小猴小程序调试技术第三版进行展开。 在上一篇导读文章中提到&#xff0c;小猴小程序的调试部分从无到有一共经历了3个版本。本篇文章会详细描述面向开发者的调试功能是如何实现的。 文章将会描述以下部分&#xff1a; 调试实现的基本通信关系结构。如何实现…

论文浅尝 - CIKM2020 | 用于推荐系统的多模态知识图谱

论文笔记整理&#xff1a;王琰&#xff0c;东南大学硕士。来源&#xff1a;CIKM 2020链接&#xff1a;https://doi.org/10.1145/3340531.3411947研究背景与任务描述为了解决推荐系统中的数据稀疏和冷启动问题&#xff0c;研究人员通过利用有价值的外部知识作为辅助信息&#xf…

FedNLP: 首个联邦学习赋能NLP的开源框架,NLP迈向分布式新时代

文 | 阿毅两周前&#xff0c;南加大Yuchen Lin&#xff08;PhD student USC and ex-research intern GoogleAI)所在的团队在Twitter官宣开源首个以研究为导向的联邦学习赋能NLP的FedNLP框架。发布数小时内就获得了647个赞&#xff0c;163次转发&#xff0c;可见其热度。我相信大…

LeetCode 380. 常数时间插入、删除和获取随机元素(哈希+vector)

1. 题目 设计一个支持在平均 时间复杂度 O(1) 下&#xff0c;执行以下操作的数据结构。 insert(val)&#xff1a;当元素 val 不存在时&#xff0c;向集合中插入该项。 remove(val)&#xff1a;元素 val 存在时&#xff0c;从集合中移除该项。 getRandom&#xff1a;随机返回现…

论文浅尝 - ICLR2020 | 知识图谱中数值规则的可微学习

论文笔记整理&#xff1a;许泽众&#xff0c;浙江大学博士研究生。研究方向&#xff1a;知识图谱&#xff0c;规则挖掘等。论文链接&#xff1a;https://openreview.net/pdf?idrJleKgrKwS本文解决的是规则的学习问题&#xff0c;学习出来的规则可用于知识推理任务&#xff0c;…

2021大厂面试高频100题最新汇总(附答案详解)

昨天在知乎上刷到一个热门问题:程序员需要达到什么水平才能顺利拿到 20k 无压力&#xff1f;其中一个最热门的回答是&#xff1a;“其实&#xff0c;无论你是前端还是后端、想进大厂还是拿高薪&#xff0c;算法都一定很重要。”为什么&#xff0c;算法会如此重要&#xff1f;不…

LeetCode 33. 搜索旋转排序数组(二分查找)

1. 题目 假设按照升序排序的数组在预先未知的某个点上进行了旋转。 ( 例如&#xff0c;数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。 搜索一个给定的目标值&#xff0c;如果数组中存在这个目标值&#xff0c;则返回它的索引&#xff0c;否则返回 -1 。 你可以假设数…

论文浅尝 - EMNLP2020 | 低资源跨语言实体链接中的设计挑战

论文笔记整理&#xff1a;谭亦鸣&#xff0c;东南大学博士。来源&#xff1a;EMNLP 2020链接&#xff1a;https://arxiv.org/pdf/2005.00692.pdf1.背景介绍跨语言实体链接&#xff08;XEL&#xff09;旨在将任一非英语文本中的实体提及匹配到英语知识库上&#xff08;例如Wikip…

MSON,让JSON序列化更快

问题 我们经常需要在主线程中读取一些配置文件或者缓存数据&#xff0c;最常用的结构化存储数据的方式就是将对象序列化为JSON字符串保存起来&#xff0c;这种方式特别简单而且可以和SharedPrefrence配合使用&#xff0c;因此应用广泛。但是目前用到的Gson在序列化JSON时很慢&a…

屠榜各大CV任务!「百度顶会论文复现营」携Swin Transformer来袭!

目标检测刷到58.7 AP&#xff01;实例分割刷到51.1 Mask AP&#xff01;&#xff01;语义分割在ADE20K上刷到53.5 mIoU&#xff01;&#xff01;&#xff01;......Swin Transformer持续屠榜各大CV任务&#xff0c;并且均名列前茅&#xff01;通过分层体系结构&#xff0c;带来…

百度任务型对话系统小记

意图扩展阅读&#xff1a; 古月哲亭: AAAI 2021 | 清华提出深度对齐聚类用于新意图发现&#xff1a;https://mp.weixin.qq.com/s/9dNs8TTERPdxmrVc3tF1zw 相关项目地址&#xff1a;https://github.com/thuiar/OKD-Reading-List 古月哲亭: 意图知识图谱的构建与应用&#xff1a…

论文浅尝 - EMNLP2020 | 跨媒体关键词预测: 多模态多头注意力和图像文本的统一框架...

论文笔记整理&#xff1a;柏超宇&#xff0c;东南大学硕士。文章链接&#xff1a;https://arxiv.org/pdf/2011.01565.pdf来源&#xff1a;EMNLP 2020动机社交媒体每天都会产生大量的内容。为了帮助用户快速捕捉所需内容&#xff0c;关键词预测受到越来越多的关注。尽管如此&…

从实际案例聊聊Java应用的GC优化

当Java程序性能达不到既定目标&#xff0c;且其他优化手段都已经穷尽时&#xff0c;通常需要调整垃圾回收器来进一步提高性能&#xff0c;称为GC优化。但GC算法复杂&#xff0c;影响GC性能的参数众多&#xff0c;且参数调整又依赖于应用各自的特点&#xff0c;这些因素很大程度…

LeetCode 162. 寻找峰值(二分查找)

1. 题目 峰值元素是指其值大于左右相邻值的元素。 给定一个输入数组 nums&#xff0c;其中 nums[i] ≠ nums[i1]&#xff0c;找到峰值元素并返回其索引。 数组可能包含多个峰值&#xff0c;在这种情况下&#xff0c;返回任何一个峰值所在位置即可。 你可以假设 nums[-1] n…

谷歌:CNN击败Transformer,有望成为预训练界新霸主!LeCun却沉默了...

文 | ????????????????这几年&#xff0c;大家都说深度学习进入了预训练时代。作为一个入行不久的小白&#xff0c;我一直以为各类基于 Transformers 结构的预训练模型是 NLP 的巨大里程碑&#xff0c;CNN、RNN 老矣&#xff0c;只配作为手下败将。大家的文章似…