1.vue runtime源码分析学习——day4:createApp
2.如何在html输入框中输入数值点确定后 更改源代码并刷新页面?
3.Unity IMGUI TreeView简单探索(一)
4.如何让网页时刻保持刷新
5.使用Copyonwrite改造本地缓存
vue runtime源码分析学习——day4:createApp
在深入研究vue runtime源码时,源码我们首先确定了分析的解析路径和方法。
createApp这个关键入口点位于@vue/runtime-dom包中,源码它是解析开发者项目启动的起点。
在开始代码分析前,源码我们选择在packages\vue\__tests__\index.spec.ts中的解析美空网 源码测试用例进行,通常选择第一个即可,源码因为这里模拟的解析是客户端环境,但需确保testEvironment配置正确并配合jsdom库使用。源码
createApp方法内部包含一些开发环境特有的解析检查,如injectCompilerOptionsCheck和injectNativeTagCheck,源码它们在生产环境不会执行。解析通过Object.defineProperty绑定,源码可以防止这些检查被意外修改。解析企业发票系统源码
createApp的源码主要任务包括调用ensureRenderer、createAppApi和mount等。其中,ensureRenderer涉及到typescript的重载,而createAppApi则是通过缓存render和hydrate方法,优化性能。
在render部分,我们首次遇到reload,这是与vue-loader中热更新功能的联系点。尽管loader中的reload方法不接受参数,但它们本质上是处理相同逻辑的。
mount方法的核心内容是将js代码转化为DOM,它会处理createVNode和vnode的题材资金指标源码生成,以及与container._vnode的更新和比对,即旧vnode与新vnode的差异处理。
虽然今天的内容可能略显琐碎,但createApp的总体流程已经清晰了。后续将继续深入解析其他关键部分。
如何在html输入框中输入数值点确定后 更改源代码并刷新页面?
<a href="javascript:location.reload();">点击刷新页面</a>
reload函数介绍: reload() 方法用于重新加载当前文档。
如果该方法没有规定参数,或者参数是 false,它就会用 HTTP 头 If-Modified-Since 来检测服务器上的文档是否已改变。如果文档已改变,reload() 会再次下载该文档。如果文档未改变,则该方法将从缓存中装载文档。html网站维护源码这与用户单击浏览器的刷新按钮的效果是完全一样的。
如果把该方法的参数设置为 true,那么无论文档的最后修改日期是什么,它都会绕过缓存,从服务器上重新下载该文档。这与用户在单击浏览器的刷新按钮时按住 Shift 健的效果是完全一样。
Unity IMGUI TreeView简单探索(一)
因为感觉可能即将要用上了,因为我想做个魔兽地图编辑器触发编辑器的那种树状的编辑器,但并不是完全照搬,就是参考一下树的结构。
因为那个对话框我没找到有啥接口,能让它挡住整个界面的输入,除非它关闭,天量战法源码我又不想在EditorWindow里自己另外实现一个嵌套窗口,嗯,所以做点妥协。参数也在树结构里好了。
这篇文章就简单记录一下简单探索的得到的内容,在寻找解决问题的路上努力,以及最后自我麻痹的过程吧。
首先需要继承TreeView这个类才能进行开始,那个TreeViewState直接new就行。
搞定之后调用一遍Reload。然后你在Window的OnGUI那边提供Rect参数并调用它的绘制方法就好啦!
在那之前你的类必须实现BuildRoot方法,在你搞定之后调用一下SetupParentsAndChildrenFromDepths这个方法,它的作用是根据depth关系去设定节点(TreeViewItem)之间的父子关系。
与之对应的还有SetupDepthsFromParentsAndChildren,根据depth设定父子关系,具体情况具体使用了。
另外,不管是Reload还是打开关闭折叠,都会去调用BuildRows。区别就是前者连BuildRoot也会调用BuildRows是根据Root去生成一个List给TreeView使用用作画面渲染,每当结构发生改变的时候,都得重新构造一遍。
所以当你Add或者Remove等导致树结构发生改变的时候,直接调用Reload,不要有心理负担。
我去看过源码,直接调用TreeViewItem的AddChild方法在显示方面上是会有出问题的,你还得去处理层级问题,以及调用它的SetExpanded false然后true。因为你不调用的话,他就不会刷新结构,你新加的节点他就会看不见。至少我觉得挺离谱的,说不定我误解了他的设计也说不定。关键的东西全给private或internal了,也没看到接口放出来(如果有大佬知道的话可以告诉我一下呀,反射就免了!)
你可能在想,我可以直接调用BuildRows呀!没用的,TreeView内部的那个controller还是dataSource根本就没同步到,在下一帧就会报错。
无论你怎么改通过GetRows拿到的列表的结构也没屁用。还是老老实实像官方一样直接粗暴的Reload。(如果有更好的方法谁愿意这么干呢?)
说实话我只是不想因为层级变动就直接重新生成整个结构,或者你直接将list缓存起来,判断一下啥也不做也行,但我强迫症犯了。
我浪费了很多时间去寻找解决方案,最后还是放弃了。最后打算参考官方的那个TreeViewWithTreeModel的做法。
反正本来就是为了给某些结构做可视化显示嘛…就用这些理由麻痹自己钻牛角尖的心吧。
基本上一些基础的使用光是看文档或者官方示例就能明白要怎么用了,所以我有点懒得写…
诸如改名操作,拖拽操作,双击项,右键项(Context,一般拿来弹个ContextMenu用)
增(TreeViewItem.AddChild)删(TreeViewItem.children.Remove)查(TreeView.FindItem FindRows)改啊啥的…
简单随便看两眼,有需要再去查文档,没必要全部硬塞进去。有空就看看官方怎么做的好了,先有点本事了能用得起来,以后再追求那些。
官网的阅读案例顺序比较推荐从
Simple Tree Window
Transform Hierarchy
Custom Row Heights
Multi Columns
看起
先看他们的window看个大概,再有啥想知道的不懂的看view的实现。
以上我说到的那些,诸如“下一帧”的这些全是我主观看法,没去验证,酌情阅读吧。
如果有什么更好的方法也希望有大佬能够指出来,感激不尽。
(百度了大半年搜的文章全部都避开了RemoveChild和AddChild来写,很棒~)
(另外预览怎么把我的排版全干掉了……?罢了)
如何让网页时刻保持刷新
一、自动刷新页面的方法:
1.页面自动刷新:把如下代码加入<head>区域中
<meta /s/blog_5fb8ecfp0.html
使用Copyonwrite改造本地缓存
背景
周四下午正在吃的下午茶,偷闲刷了一会手机(光明正大的),突然就有客服中心的**姐找上门来说xxx操作又出现失败了,但是多点几次又没问题了(之前也出现过,可是代码中没有任何异常处理和日志的输出很难排查,没办法老代码,前任写的我也没办法,只能加上等复现的时候再看看),看着**姐焦急的表情,下午茶瞬间就不香了,找bug去!
产生原因定位在rancher上输入账号找到对应的服务,根据关键字找到相关日志映入眼帘的是java.lang.NullPointException跟随报错的行数找到了相关代码块:
if(StringUtils.isNotEmpty(feeSetting.getFileId())){ returnschoolService.deal(sysConfigService.getString("url"));}其中报错的是
schoolService.deal(sysConfigService.getString("url"));定位问题,应该是调用StringgetString(Stringkey);空指针导致的.
分析相关代码:
publicStringgetString(Stringkey){ if(configs==null){ initConfig();}returnconfigs.get(key);}其中initConfig()的实现:
privatevoidinitConfig(){ synchronized(lock){ if((configs==null)||configs.isEmpty()){ configs=newHashMap<String,String>();//从db中加载到configsloadSysConfig();}}}其中configs是个成员变量
privatestaticMap<String,String>configs=null;复制代码查了一下数据库,有对应的数据存在,不是数据的问题
getString(Stringkey)接口内部没报错,说明这个程序没报错
抓了抓头(有点意思),只有Map中没有相应的数据才有可能报空指针,查找了相关方法,找到了如下代码:
publicvoidreload(){ if((configs!=null)&&!configs.isEmpty()){ configs.clear();this.initConfig();}}只有一处调用该方法
@ComponentpublicclassSysConfgMQListenerimplementsMessageListenerConcurrently{ protectedfinalLoggerlog=LoggerFactory.getLogger(SysConfgMQListener.class);@AutowiredprivateISysConfigServicesysConfigService;@OverridepublicConsumeConcurrentlyStatusconsumeMessage(List<MessageExt>msgs,ConsumeConcurrentlyContextcontext){ log.info("SysConfgMQListenerretrieving...");for(MessageExtmsg:msgs){ log.info("messageExt,body:{ }",newString(msg.getBody()));this.sysConfigService.reload();}returnConsumeConcurrentlyStatus.CONSUME_SUCCESS;}}这是RocketMq的消费者这里调用了,而且还是广播模式,所有节点都能消费,这个Mq的生产者是在后台触发刷新时候产生的.
真相只有一个首先触发Mq的消费,导致Map刷新,重新加载调用reload()
当执行configs.clear();之后Map就是一个空对象,没有任何数据
如果这个时候是有多个线程访问getString(Stringkey)获取到的值就是null
改造第一个想到的是用Redis来替换,但是很快就自我否定了,这个接口在没有触发刷新机制的前提下运行了几年是好好的,而且基础配置放Redis的话过期时间的设置不好判断,并且还要多个IO的传递,性能没有本地的Map好.
第二个想到的方案就是在getString(Stringkey)方法中加锁,这只能当做下下策
正在一筹莫展的时候,突然灵光一闪,这不是跟注册中心很像吗?各个客户端去拉取数据,而nacos为了高性能就是用了Copyonwrite的思想来实现的,越想越行,干!
代码改造如下:
publicvoidreload(){ if((configs!=null)&&!configs.isEmpty()){ //先清除再加载会出现,在两个操作之间请求的接口获取都为空//configs.clear();//this.initConfig();this.reloadForConfigs();}}其中this.reloadForConfigs();
privatevoidreloadForConfigs(){ Map<String,String>newConfigs=newHashMap<>();try{ List<Config>datas=configDao.listConfigs();if(datas!=null){ for(Configcf:datas){ newConfigs.put(cf.getKey(),cf.getValue());}}}catch(Exceptione){ LogUtil.exception(log,e);}if(CollectionUtil.isNotEmpty(newConfigs)){ //替换旧的this.configs=newConfigs;}}这改造完上线之后,跟踪了一段时间日志中也没发现空指针(**姐也不来找我了-_-,不开森),有那么一点点的成就感.
总结开发的时候要考虑多线程和并发场景
遇到问题别慌,认真分析
好的方案不是一蹴而就的
多读好的代码如框架源码,不断的积累,现在用不上,某一时刻就用上了
作者:董懂