前端开发者福音,一定要试试的 Web 远程调试工具!
GitHub 库房地址:github.com/HuolalaTech…
前言
PageSpy 自开源供给服务以来,社区中收到很多用户反应说想了解 PageSpy 的一些工作原理,这么真诚而又火热的要求,咱们第一时间安排上了。本章就为咱们带来深化完结原理系列之「打印 window 方针,PageSpy 是怎么处理的?」。
Console 面板除了打印日志外,还支撑在 Console 面板底部发送调试代码到客户端,获取运行时的变量信息。
还没有尝试过的小伙伴能够点击 在线体验,接下来将和咱们一同进入主题:PageSpy 怎么处理杂乱数据的交互。
规划方针
PageSpy Console 面板最起初的规划方针便是向浏览器控制台的 Console 面板看齐。用户假如打印杂乱数据,单纯靠序列化源数据会面临以下问题:
- 不支撑序列化的特点值会丢掉;
-
self-reference
的数据会报错; -
Getter
特点值动态计算的交互特性会丢掉; - 无法沿着原型链查看数据明细;
上述说到的每一项在各自的场景中都发挥着无比重要的作用。所以能够明确的是:
- 想要打印杂乱数据,肯定是需要先做什么处理后再运用;
- 后续有查看特点明细的需求,所以需要将数据实体找个地方存起来;
什么是杂乱数据?
关于数据「杂乱不杂乱」是依照如下界说的:
- 能够点击查看明细的数据都是杂乱数据,如
Object
/Array
/Set
/Map
等类型的数据; - 一眼就看明白的都是不杂乱数据,如
"Hello"
/12345
/true
/Symbol(foo)
/Error
/undefined
等;
在 PageSpy 中,咱们将对各种数据进行转化、缓存、查询、交互的逻辑封成 Atom
类(type: "atom"
代表杂乱数据),结构体如下所示:
// SpyAtom.Overview
interface Overview {
id: string;
type:
| 'string'
| 'number'
| 'bigint'
| 'boolean'
| 'symbol'
| 'undefined'
| 'object'
| 'function'
| 'null'
| 'error'
| 'debug-origin'
| 'atom';
value: string | PropertyDescriptor;
__atomId?: string;
instanceId?: string;
}
正是这 20 行类型代码决定了本次主题中的详细完结:打印 window 方针便是依赖这套接口类型界说。
为什么要强调打印的是 window
方针?因为 window
方针具有上述一切的 “问题” 于一身:
- 有不支撑序列化的特点数据,比如
window.alert()
这种大局方法的特点; - 有很多
Getter
特点,如outerWidth
/innerWidth
/location
等; - self-reference,如
window.self
; - 能够沿着原型链查看数据明细;
怎么完结
咱们在上面说到了:「用户假如打印杂乱数据,单纯靠序列化源数据会面临……」,那打印不杂乱数据还会有那么多问题吗?答案是不会,关于这些不杂乱的数据咱们只需要拿到值,并获取到它的类型即可完结烘托。
明确了数据复不杂乱之后,咱们从以上类型界说中把 type: "atom"
杂乱数据类型的界说独自拎出来:
// SpyAtom.Overview
interface Overview {
id: string;
type: 'atom';
value: string | PropertyDescriptor;
__atomId: string;
instanceId: string;
}
- id:作为数据的仅有标识。
-
__atomId:打印杂乱数据时,数据实体会被记录在 Atom 的 storeMap 中,
__atomId
在 storeMap 中作为 key,对应一个方针源数据。 -
instanceId:实质的值是由
__atomId
衍生。默许和__atomId
持平、指向当时打印出来的方针;点击方针打开,每个内层特点都有一个instanceId
指向父级(上一层)的方针;
除了以上三个 id 之外,咱们还用到了一个被称为 parentId
的数据:
-
parentId:实质的值也是由
__atomId
衍生。用于获取Getter
特点值,详细的获取行为原理是Object.getOwnPropertyDescriptor(store[parentId], key).get.call(store[instanceId])
总结
经过以上的内容介绍,咱们再来回顾下打印 window
方针会遇到的问题,现在都有了相对应的答案:
怎么处理不支撑序列化的特点数据,比如函数?
答:第一步先经过获取类型将数据以「杂乱」维度区分,结合数据值来描绘一个数据该怎么显现;而函数归于不杂乱数据,在确定是函数类型后、经过 fn.toString()
获取值即可在调试端烘托。
Getter
特点动态计算特点值的交互特性会丢掉?
答:Getter
特点值的获取实质上是调用函数,函数体内会运用 this
指针。那么根据以上杂乱数据结构的界说,咱们有 parentId / key / instanceId,根据 parentId 和 key 能够获取 getter 函数自身,再经过 instanceId 知道了实例方针,那么接下来组合调用一下就能完美解决:Object.getOwnPropertyDescriptor(store[parentId], key).get.call(store[instanceId])
;
怎么处理 self-reference
方针无法序列化的问题,如 window.self
?
答:PageSpy 只会转化当时方针层级下的不杂乱的数据特点。打开 window 时,PageSpy 会拿到 self
特点,但判别出它是一个杂乱数据,SDK 不会直接进行计算、转化处理,而是告知调试端 window.self
的描绘符具有 getter 特点,等待调试端下次来查询时,再进值计算并返回值。
怎么沿着原型链查看数据明细?
答:虽然经过 Object.getOwnPropertyDescriptors(someObj)
返回的 descriptors
描绘符不会给咱们原型方针的数据,可是咱们能够手动增加一个 [[Prototype]]
加上去就能够满足用户沿着原型链点击查看数据明细啦!
以上便是本次深化 PageSpy 完结原理系列文章的全部内容了,欢迎咱们在工作中集成运用,遇到问题能够在 Github 反应或许参加技术支撑群(中文 README 有群二维码),咱们将第一时间解答。