「Vue源码学习」常见的 Vue 源码面试题,看完可以说 “精通Vue” 了吗?
Vue源码面试题
- 一、行时(Runtime)+ 编译器(Compiler) vs. 只包含运行时(Runtime-only)
- webpack
- Rollup
- Browserify
- 二、Vue 的初始化过程(
- 面试关问:new Vue(options) 发生了什么?
- 三、响应式原理
- 1. 面试官 问:Vue 响应式原理是怎么实现的?
- 答:
- 2. 面试官问:methods、computed 和 watch 有什么区别?
- 答:
- 四、异步更新
- 1. 面试官 问:Vue 的异步更新机制是如何实现的?
- 答:
- 2. 面试关 问:Vue 的 nextTick API 是如何实现的?
- 答:
- 五、全局API
- 1. 面试官 问:Vue.use(plugin) 做了什么?
- 答:
- 2. 面试官 问:Vue.mixin(options) 做了什么?
- 答:
- 3. 面试官 问:Vue.component(compName, Comp) 做了什么?
- 答:
- 4. 面试官 问:Vue.directive('my-directive', {xx}) 做了什么?
- 答:
- 5. 面试官 问:Vue.filter('my-filter', function(val) {xx}) 做了什么?
- 答:
- 6. 面试官 问:Vue.extend(options) 做了什么?
- 答:
- 7. 面试官 问:Vue.set(target, key, val) 做了什么
- 答:
- 8. 面试官 问:Vue.delete(target, key) 做了什么?
- 答:
- 9. 面试官 问:Vue.nextTick(cb) 做了什么?
- 答:
- 六、实例方法
- 1. 面试官 问:vm.$set(obj, key, val) 做了什么?
- 答:
- 博主最近在准备面试,未完待续!
一、行时(Runtime)+ 编译器(Compiler) vs. 只包含运行时(Runtime-only)
-如果你需要动态编译模版(比如:将字符串模版传递给 template 选项,或者通过提供一个挂载元素的方式编写 html 模版),你将需要编译器,因此需要一个完整的构建包。
当你使用 vue-loader 或者 vueify 时,*.vue 文件中的模版在构建时会被编译为 JavaScript 的渲染函数。因此你不需要包含编译器的全量包,只需使用只包含运行时的包即可。
只包含运行时的包体积要比全量包的体积小 30%。因此尽量使用只包含运行时的包,如果你需要使用全量包,那么你需要进行如下配置:
webpack
module.exports = {// ...resolve: {alias: {'vue$': 'vue/dist/vue.esm.js'}}
}
Rollup
const alias = require('rollup-plugin-alias')rollup({// ...plugins: [alias({'vue': 'vue/dist/vue.esm.js'})]
})
Browserify
{// ..."browser": {"vue": "vue/dist/vue.common.js"}
}
二、Vue 的初始化过程(
面试关问:new Vue(options) 发生了什么?
从入口代码开始分析,我们先来分析 new Vue 背后发生了哪些事情。我们都知道,new 关键字在 Javascript 语言中代表实例化是一个对象,而 Vue 实际上是一个类,类在 Javascript 中是用 Function 来实现的,来看一下源码,在src/core/instance/index.js 中。
function Vue (options) {if (process.env.NODE_ENV !== 'production' &&!(this instanceof Vue)) {warn('Vue is a constructor and should be called with the `new` keyword')}this._init(options)
}
可以看到 Vue 只能通过 new 关键字初始化,然后会调用 this._init 方法, 该方法在 src/core/instance/init.js 中定义。
Vue.prototype._init = function (options?: Object) {const vm: Component = this// a uidvm._uid = uid++let startTag, endTag/* istanbul ignore if */if (process.env.NODE_ENV !== 'production' && config.performance && mark) {startTag = `vue-perf-start:${vm._uid}`endTag = `vue-perf-end:${vm._uid}`mark(startTag)}// a flag to avoid this being observedvm._isVue = true// merge optionsif (options && options._isComponent) {// optimize internal component instantiation// since dynamic options merging is pretty slow, and none of the// internal component options needs special treatment.initInternalComponent(vm, options)} else {vm.$options = mergeOptions(resolveConstructorOptions(vm.constructor),options || {},vm)}/* istanbul ignore else */if (process.env.NODE_ENV !== 'production') {initProxy(vm)} else {vm._renderProxy = vm}// expose real selfvm._self = vminitLifecycle(vm)initEvents(vm)initRender(vm)callHook(vm, 'beforeCreate')initInjections(vm) // resolve injections before data/propsinitState(vm)initProvide(vm) // resolve provide after data/propscallHook(vm, 'created')/* istanbul ignore if */if (process.env.NODE_ENV !== 'production' && config.performance && mark) {vm._name = formatComponentName(vm, false)mark(endTag)measure(`vue ${vm._name} init`, startTag, endTag)}if (vm.$options.el) {vm.$mount(vm.$options.el)}
}
Vue 初始化主要就干了几件事情,合并配置,初始化生命周期,初始化事件中心,初始化渲染,初始化 data、props、computed、watcher 等等。
三、响应式原理
1. 面试官 问:Vue 响应式原理是怎么实现的?
答:
-
响应式的核心是通过
Object.defineProperty拦截对数据的访问和设置 -
响应式的数据分为两类:
- 添加新数据时进行响应式处理,然后由 dep 通知 watcher 去更新
- 删除数据时,也要由 dep 通知 watcher 去更新
- 访问数据时(obj.key)进行依赖收集,在 dep 中存储相关的 watcher
- 设置数据时由 dep 通知相关的 watcher 去更新
- 对象,循环遍历对象的所有属性,为每个属性设置 getter、setter,以达到拦截访问和设置的目的,如果属性值依旧为对象,则递归为属性值上的每个 key 设置 getter、setter
- 数组,增强数组的那 7 个可以更改自身的原型方法,然后拦截对这些方法的操作
2. 面试官问:methods、computed 和 watch 有什么区别?
答:
<!DOCTYPE html>
<html lang="en"><head><title>methods、computed、watch 有什么区别</title>
</head><body><div id="app"><!-- methods --><div>{{ returnMsg() }}</div><div>{{ returnMsg() }}</div><!-- computed --><div>{{ getMsg }}</div><div>{{ getMsg }}</div></div><script src="../../dist/vue.js"></script><script>new Vue({el: '#app',data: {msg: 'test'},mounted() {setTimeout(() => {this.msg = 'msg is changed'}, 1000)},methods: {returnMsg() {console.log('methods: returnMsg')return this.msg}},computed: {getMsg() {console.log('computed: getMsg')return this.msg + ' hello computed'}},watch: {msg: function(val, oldVal) {console.log('watch: msg')new Promise(resolve => {setTimeout(() => {this.msg = 'msg is changed by watch'}, 1000)})}}})</script>
</body></html>
- 使用场景
methods一般用于封装一些较为复杂的处理逻辑(同步、异步)computed一般用于封装一些简单的同步逻辑,将经过处理的数据返回,然后显示在模版中,以减轻模版的重量watch一般用于当需要在数据变化时执行异步或开销较大的操作
- 区别
-
methods VS computed
如果在一次渲染中,有多个地方使用了同一个 methods 或 computed 属性,methods 会被执行多次,而 computed 的回调函数则只会被执行一次。
在一次渲染中,多次访问
computedProperty,只会在第一次执行computed属性的回调函数,后续的其它访问,则直接使用第一次的执行结果(watcher.value),而这一切的实现原理则是通过对watcher.dirty属性的控制实现的。而methods,每一次的访问则是简单的方法调用(this.xxMethods)。 -
computed VS watch
computed 和 watch 的本质是一样的,内部都是通过
Watcher来实现的,其实没什么区别,非要说区别的话就两点:1、使用场景上的区别,2、computed 默认是懒执行的,切不可更改。 -
methods VS watch
methods 和 watch 之间其实没什么可比的,完全是两个东西,不过在使用上可以把 watch 中一些逻辑抽到 methods 中,提高代码的可读性。
-
四、异步更新
1. 面试官 问:Vue 的异步更新机制是如何实现的?
答:
Vue 的异步更新机制的核心是利用了浏览器的异步任务队列来实现的,首选微任务队列,宏任务队列次之。
-
当响应式数据更新后,会调用
dep.notify方法,通知 dep 中收集的watcher去执行update方法,watcher.update 将 watcher 自己放入一个watcher 队列(全局的queue 数组)。 -
然后通过
nextTick方法将一个刷新 watcher 队列的方法(flushSchedulerQueue)放入一个全局的callbacks数组中。 -
如果此时浏览器的异步任务队列中没有一个叫
flushCallbacks的函数,则执行timerFunc函数,将 flushCallbacks 函数放入异步任务队列。如果异步任务队列中已经存在 flushCallbacks 函数,等待其执行完成以后再放入下一个 flushCallbacks 函数。
flushCallbacks 函数负责执行 callbacks 数组中的所有
flushSchedulerQueue函数。
flushSchedulerQueue 函数负责刷新 watcher 队列,即执行 queue 数组中每一个 watcher 的 run 方法,从而进入更新阶段,比如执行组件更新函数或者执行用户 watch 的回调函数。
2. 面试关 问:Vue 的 nextTick API 是如何实现的?
答:
Vue.nextTick 或者 vm.$nextTick 的原理其实很简单,就做了两件事:
-
将传递的回调函数用
try catch包裹然后放入callbacks数组 -
执行
timerFunc函数,在浏览器的异步任务队列放入一个刷新 callbacks 数组的函数
五、全局API
1. 面试官 问:Vue.use(plugin) 做了什么?
答:
负责安装 plugin 插件,其实就是执行插件提供的 install 方法。
- 首先判断该插件是否已经安装过
- 如果没有,则执行插件提供的 install 方法安装插件,具体做什么有插件自己决定
2. 面试官 问:Vue.mixin(options) 做了什么?
答:
负责在 Vue 的全局配置上合并 options 配置。然后在每个组件生成 vnode 时会将全局配置合并到组件自身的配置上来。
- 标准化 options 对象上的 props、inject、directive 选项的格式
- 处理 options 上的 extends 和 mixins,分别将他们合并到全局配置上
- 然后将 options 配置和全局配置进行合并,选项冲突时 options 配置会覆盖全局配置
3. 面试官 问:Vue.component(compName, Comp) 做了什么?
答:
负责注册全局组件。其实就是将组件配置注册到全局配置的 components 选项上(options.components),然后各个子组件在生成 vnode 时会将全局的 components 选项合并到局部的 components 配置项上。
- 如果第二个参数为空,则表示获取 compName 的组件构造函数
- 如果 Comp 是组件配置对象,则使用 Vue.extend 方法得到组件构造函数,否则直接进行下一步
- 在全局配置上设置组件信息,this.options.components.compName = CompConstructor
4. 面试官 问:Vue.directive(‘my-directive’, {xx}) 做了什么?
答:
在全局注册 my-directive 指令,然后每个子组件在生成 vnode 时会将全局的 directives 选项合并到局部的 directives 选项中。原理同 Vue.component 方法:
- 如果第二个参数为空,则获取指定指令的配置对象
- 如果不为空,如果第二个参数是一个函数的话,则生成配置对象
- 然后将指令配置对象设置到全局配置上,
this.options.directives['my-directive'] = {xx}
5. 面试官 问:Vue.filter(‘my-filter’, function(val) {xx}) 做了什么?
答:
负责在全局注册过滤器 my-filter,然后每个子组件在生成 vnode 时会将全局的 filters 选项合并到局部的 filters 选项中。原理是:
- 如果没有提供第二个参数,则获取 my-filter 过滤器的回调函数
- 如果提供了第二个参数,则是设置
this.options.filters['my-filter'] = function(val) {xx}
6. 面试官 问:Vue.extend(options) 做了什么?
答:
Vue.extend 基于 Vue 创建一个子类,参数 options 会作为该子类的默认全局配置,就像 Vue 的默认全局配置一样。所以通过 Vue.extend 扩展一个子类,一大用处就是内置一些公共配置,供子类的子类使用。
- 定义子类构造函数,这里和 Vue 一样,也是调用 _init(options)
- 合并 Vue 的配置和 options,如果选项冲突,则 options 的选项会覆盖 Vue 的配置项
- 给子类定义全局 API,值为 Vue 的全局 API,比如
Sub.extend = Super.extend,这样子类同样可以扩展出其它子类- 返回子类 Sub
7. 面试官 问:Vue.set(target, key, val) 做了什么
答:
由于 Vue 无法探测普通的新增 property (比如 this.myObject.newProperty = ‘hi’),所以通过 Vue.set 为向响应式对象中添加一个 property,可以确保这个新 property 同样是响应式的,且触发视图更新。
- 更新数组指定下标的元素:Vue.set(array, idx, val),内部通过 splice 方法实现响应式更新
- 更新对象已有属性:Vue.set(obj, key ,val),直接更新即可 =>
obj[key] = val- 不能向 Vue 实例或者 $data 动态添加根级别的响应式数据
- Vue.set(obj, key, val),如果 obj 不是响应式对象,会执行
obj[key] = val,但是不会做响应式处理- Vue.set(obj, key, val),为响应式对象 obj 增加一个新的 key,则通过 defineReactive 方法设置响应式,并触发依赖更新
8. 面试官 问:Vue.delete(target, key) 做了什么?
答:
删除对象的 property。如果对象是响应式的,确保删除能触发更新视图。这个方法主要用于避开 Vue 不能检测到 property 被删除的限制,但是你应该很少会使用它。当然同样不能删除根级别的响应式属性。
- Vue.delete(array, idx),删除指定下标的元素,内部是通过 splice 方法实现的
- 删除响应式对象上的某个属性:
Vue.delete(obj, key),内部是执行 delete obj.key,然后执行依赖更新即可
9. 面试官 问:Vue.nextTick(cb) 做了什么?
答:
Vue.nextTick(cb) 方法的作用是延迟回调函数 cb 的执行,一般用于 this.key = newVal 更改数据后,想立即获取更改过后的 DOM 数据:
this.key = 'new val'Vue.nextTick(function() {// DOM 更新了
})
其内部的执行过程是:
this.key = 'new val,触发依赖通知更新,将负责更新的 watcher 放入 watcher 队列- 将刷新 watcher 队列的函数放到 callbacks 数组中
- 在浏览器的异步任务队列中放入一个刷新 callbacks 数组的函数
- Vue.nextTick(cb) 来插队,将 cb 函数放入 callbacks 数组
- 待将来的某个时刻执行刷新 callbacks 数组的函数
- 然后执行 callbacks 数组中的众多函数,触发 watcher.run 的执行,更新 DOM
- 由于 cb 函数是在后面放到 callbacks 数组,所以这就保证了先完成的 DOM 更新,再执行 cb 函数
六、实例方法
1. 面试官 问:vm.$set(obj, key, val) 做了什么?
答:
vm.$set用于向响应式对象添加一个新的property,并确保这个新的 property 同样是响应式的,并触发视图更新。由于 Vue 无法探测对象新增属性或者通过索引为数组新增一个元素,比如:this.obj.newProperty = 'val'、this.arr[3] = 'val'。所以这才有了 vm.$set,它是 Vue.set 的别名。
- 为对象添加一个新的响应式数据:调用 defineReactive 方法为对象增加响应式数据,然后执行 dep.notify 进行依赖通知,更新视图
- 为数组添加一个新的响应式数据:通过 splice 方法实现
博主最近在准备面试,未完待续!
相关文章:
「Vue源码学习」常见的 Vue 源码面试题,看完可以说 “精通Vue” 了吗?
Vue源码面试题一、行时(Runtime) 编译器(Compiler) vs. 只包含运行时(Runtime-only)webpackRollupBrowserify二、Vue 的初始化过程(面试关问:new Vue(options) 发生了什么࿱…...
FreeModbus RTU 移植指南
FreeModbus 简介 FreeModbus 是一个免费的软件协议栈,实现了 Modbus 从机功能: 纯 C 语言支持 Modbus RTU/ASCII支持 Modbus TCP 本文介绍 Modbus RTU 移植。 移植环境: 裸机Keil MDK 编译器Cortex-M3 内核芯片(LPC1778/88&…...
《唐诗三百首》数据源网络下载
2023年的 元宵之夜,这场以“长安”为主题的音乐会火了!在抖音,超过2300万人次观看了直播,在线同赏唐诗与交响乐的融合。许多网友惊呼,上学时那些害怕背诵的诗句,原来还可以有这么美的表达这场近80分钟的音乐…...
(深度学习快速入门)第五章第一节2:GAN经典案例之MNIST手写数字生成
获取pdf:密码7281 文章目录一:数据集介绍二:GAN简介(1)简介(2)损失函数三:代码编写(1)参数及数据预处理(2)生成器与判别器模型&#x…...
雁过留痕,竟是病毒的痕迹?
凌恩生物全新升级宏病毒组分析流程;聚焦DNA,RNA病毒组研究热点;高灵敏度检测vOTUs;多软件整合,精准鉴定病毒序列;直击地化循环关键环节,助力宏病毒组科研成功!期刊:Micro…...
Linux基本功系列之sort命令实战
文章目录前言一. sort命令介绍二. 语法格式及常用选项三. 参考案例3.1 按照文本默认排序3.2 忽略相同的行3.3 按数字大小进行排序3.4 检查文件是否已经按照顺序排序3.5 将第3列按照数字大小进行排序3.6 将排序结果输出到文件四. 探讨 -k的高级用法总结前言 大家好,…...
【笔记】移动端自动化:adb调试工具+appium+UIAutomatorViewer
学习源: https://www.bilibili.com/video/BV11p4y197HQ https://blog.csdn.net/weixin_47498728/category_11818905.html 一、移动端测试环境搭建 学习目标 1.能够搭建java 环境 2.能够搭建android 环境 (一)整体思路 我们的目标是Andr…...
面试复习题--性能检测原理
1、布局性能检测 Systrace,内存优化工具中也用到了 Systrace,这里关注 Systrace 中的 Frames 页面,正常情况下圆点为绿色,当出现黄色或者红色的圆点时,表现出现了丢帧。 Layout Inspector,是 AndroidStudio 自带工具…...
@LoadBalanced 和 @RefreshScope 同时使用,负载均衡失效分析
背景 最近引入了 Nacos Config 配置管理能力,说起来用法很简单,还是踩了三个坑。 Nacos Config 的 nacos 的帐号密码加密配置后,怎么解密而且在 NacosConfigBootstrapConfiguration 真正注入 Nacos Config 注入之前,而且不能触发…...
2023年个人计划
2023年个人计划 可能是最近太清闲,感觉生活很无聊,就胡乱做下新年的规划吧,扰乱下烦闷的心 1 二宝健健康康,活泼可爱 目前老婆已经怀孕5周左右了,二宝将在进行年中降生,希望老婆少受点罪,二宝…...
加拿大访问学者家属如何办理探亲签证?
由于大多数访问学者的访学期限都为一年,家人来访不仅可以缓解访学的寂寞生活,而且也是家人到加拿大体验国外风情的好机会。家属在国内申请赴加签证时,如果材料齐全,一般上午递交了申请,下午就可以拿到签证。以下是家人…...
操作系统基础---多线程
文章目录操作系统基础---多线程1.为何引入线程程序并发的时空开销线程的设计思路线程的状态和线程控制块TCB2.线程与进程的比较3.线程的实现⭐1.内核支持线程KST2.用户级线程3.组合方式操作系统基础—多线程 1.为何引入线程 利用传统的进程概念和设计方法已经难以设计出适合于…...
2022-12-10青少年软件编程(C语言)等级考试试卷(六级)解析
2022-12-10青少年软件编程(C语言)等级考试试卷(六级)解析T1、区间合并 给定 n 个闭区间 [ai; bi],其中i1,2,...,n。任意两个相邻或相交的闭区间可以合并为一个闭区间。例如,[1;2] 和 [2;3] 可以合并为 [1;3…...
太酷了,用Python实现一个动态条形图!
大家好,我是小F~说起动态条形图,小F之前推荐过两个Python库,比如「Bar Chart Race」、「Pandas_Alive」,都可以实现。今天就给大家再介绍一个新的Python库「pynimate」,一样可以制作动态条形图,…...
单元测试junit+mock
单元测试 是什么? 单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。至于“单元”的大小或范围,并没有一个明确的标准,“单元”可以是一个方法、类、功能模块或者子系统。 单元测试通…...
2022Q4手机银行新版本聚焦提升客群专属、财富开放平台、智能化能力,活跃用户规模6.91亿人
易观:2022年第4季度,手机银行APP迭代升级加快,手机银行作为零售银行服务及经营的主阵地,与零售银行业务发展的联系日益紧密。迭代升级一方面可以顺应零售银行发展战略及方向,对手机银行业务布局进行针对性调整优化&…...
YOLO-V1~V3经典物体检测算法介绍
大名鼎鼎的YOLO物体检测算法如今已经出现了V8版本,我们先来了解一下它前几代版本都做了什么吧。本篇文章介绍v1-v3,后续会继续更新。一、节深度学习经典检测方法概述1.1 检测任务中阶段的意义我们所学的深度学习经典检测方法 ,有些是单阶段的…...
SparkSQL 核心编程
文章目录SparkSQL 核心编程1、新的起点2、SQL 语法1) 读取 json 文件创建 DataFrame2) 对 DataFrame 创建一个临时表3) 通过SQL语句实现查询全表3、DSL 语法1) 创建一个DataFrame2) 查看DataFrame的Schema信息3) 只查看"username"列数据4) 查看"username"列…...
Android核心开发【UI绘制流程解析+原理】
一、UI如何进行具体绘制 UI从数据加载到具体展现的过程: 进程间的启动协作: 二、如何加载到数据 应用从启动到onCreate的过程: Activity生产过程详解: 核心对象 绘制流程源码路径 1、Activity加载ViewRootImpl ActivityThread…...
计算机组成原理第七章笔记记录
仅仅作为笔记记录,B站视频链接,若有错误请指出,谢谢 基本概念 演变过程 I/O系统基本组成 I/O软件 包括驱动程序、用户程序、管理程序、升级补丁等 下面的两种方式是用来实现CPU和I/O设备的信息交换的 I/O指令 CPU指令的一部分,由操作码,命令码,设备…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
免费数学几何作图web平台
光锐软件免费数学工具,maths,数学制图,数学作图,几何作图,几何,AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...
从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践
作者:吴岐诗,杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言:融合数据湖与数仓的创新之路 在数字金融时代,数据已成为金融机构的核心竞争力。杭银消费金…...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
