三叶の小窝
type: channel
link: https://blog.mitsuha.space/
description: 想成为知道自己知道的人
items: 走出 IIFE 误区
items: 瓶颈期
items: 稻妻之旅
items: 博客拔草记录
items: 2023年终总结
items: 使用 React Query 优化请求！
items: 踩了个嵌套滚动的坑
items: 2022年终总结
items: 写在入职🐧两周后
items: 深入理解现代浏览器 阅读笔记五

走出 IIFE 误区
type: item
date: 2025-10-13T00:09:00+08:00
description: IIFE是立即执行函数表达式（Immediately Invoked Function Expression）的缩写。它是一种特殊的函数调用方式，也是一种用来创建函数作用域的模式。在JavaScript中，IIFE通过将函数用括号包裹，并在后面立即调用它来创建一个函数作用域。这样做的好处是可以在函数内部定义变量和函数，而不会对外部的全局作用域造成污染。这里我最开始对「不会对外部的全局作用域造成污染」的理解有点问题，IIFE内部的声明、赋值等操作都不会影响到全局作用域，是一个完全独立的作用域。抱着想试试是否有这么神奇的用法，我跑了下下面的例子。var a = 'global' // test1 内部局部变量a，不会影响全局变量a function test1() { var a = 1 a = 'test1' console.log(a) } test1() console.log(a) // test2 内部没有var，会直接修改全局变量a function test2() { a = 'test2' console.log(a) } test2() console.log(a) // test3 内部局部变量a，不会影响全局变量a ;(function () { var a = 'test3' console.log(a) })() console.log(a) // test4 内部没有var，会直接修改全局变量a ;(function () { a = 'test4' console.log(a) })() console.log(a)运行结果test1 global test2 test2 test3 test2 test4 test4其实从结果可以看出来，IIFE从作用域隔离的角度上来看其实和普通函数闭包没什么区别（其实本身也差不多是一个东西）。那么IIFE的作用到底是什么呢？其实要从比较实际的场景出发，在某次掘金冲浪中发现了这样一篇文章，解释了IIFE在没有 CommonJS 等技术时是如何实现模块化的。原文链接：从构建产物洞悉模块化原理以这个下面的HTML为例 其中 index.js 和 list.js 由 A 负责，home.js 由 B 负责。A 在 index.js 中声明var name = 'foo'并在 list.js 中使用console.log(name)结果却得到 name 变量变为了一个函数，而这是因为 B 在 home.js 中将 name 声明为了一个函数function name(){ //... }而这里如果 B 能够以 IIFE的方式来编写 home.js 则不会出现这种情况。因为 IIFE 在执行这段JS时就会立即形成闭包来进行隔离保护，甚至都不需要一个具名的方法来运行。虽然这种方式在现在看来还存在着很多提升空间，但在当时的环境下解决了全局变量污染的问题也算是给予了 JS 丰富的插件生态的发展空间（个人认为）。

瓶颈期
type: item
date: 2025-07-22T00:27:45+08:00
description: 随着2025H1考核自评提交，猛然发现今年已经过了一半。与去年下半年相比是截然不同的体验，有一种现象感觉在生活中的各个方面同时出现了——瓶颈。工作年后的一两个月我主要负责一些平台的日常需求，节奏非常稳定。慢慢习惯下来后也开始有了更多的时间在个人上，重拾了之前自己的一些小项目、用新的技术栈翻新了之前的代码。甚至和朋友（还是上篇博客提到的小Y）约定好了五一第二次日本之旅。AI像一阵风，吹完他就走，这样的节奏，谁都无可奈何~AI的风还是刮到了我们部门，我也被抓壮丁去负责了平台侧接入AI的重点项目。又是典中典之时间紧任务重、“老板要看效果”等。从3月底的某一个晚上开始，十点的工位开始频繁出现我的身影。没日没夜的加班开始了，4月初开始的一周半左右的迭代周期，到4月底的MVP版本，再到5、6月份的周迭代。其中在5月份左右，随着项目度过MVP版本，项目开始走正规一些的管理流程，我也被leader指定为了前端负责人。作为一个初出茅庐的校招生，刚开始我并不明白为什么要推我去做负责人。平时赶需求就已经占尽了我十分气力，又何来精力去协调我们组内的前辈们。虽然后来我才幡然醒悟是也许是组长有意为之想锻炼锻炼我，但对于当时的我来说险些成为了压死骆驼的稻草。好在关关难过关关过，我用更多的时间去弥补了经验的不足。项目度过了相对野蛮的发展时期，我也没有成为被压死的骆驼。一切都在朝着好的方向发展，而在过去的暗无天日的Q2，浓浓的班味还是深深地影响到了我生活的大多数时候。减肥23~24年，我通过跑步减下了差不多26斤（84kg~71kg）。这件事情真的让我改变了许多。运动与生活相结合带来的正反馈可以辐射到生活中非常多地方，带给我很多自信心和动力。让我在面对挑战和困难的时候都能更加从容一些。但随着加班日益增多、生活节奏被打乱，虽然自己还在想方设法保持运动量，可从指标上却一点看不出来——我的体重不降反增。每次上称都会对眼前的数字感到惊讶。虽然想去努力调整，但更多是心有余而力不足。疲惫下班后路过甜品店，在恶魔递出奶油点心前常常失守心神，出卖健康得到短暂的愉快与深夜的懊悔。日常学习去年入职时给自己定下了长期学习的目标，希望能形成习惯与运动一起提升身心的生活品质。主要的方向有两个：前端技术学习日语学习前者主要是靠业余时间的编码与探索进行经验积累，辅以一些经典文章与书籍。后者则主要是通过标日和多邻国等教材和软件来学习，利用碎片化时间来进行单词的背。在刚入职那一阵子感觉效果非常不错，通过订阅「Javascript Weekly」等一些优质频道进行视野拓展。再加上周末也确实会鼓捣一些小东西，感觉编码水平是有在稳步提升。日语的学习则与日常相结合，起床后、运动后都会背下单词，配合一些教材和多邻国。感觉也能够脱离番剧说两句日语了。但伴随着可支配时间逐渐减少但心中一直有着不想放弃的执念，我的学习虽然仍在继续但变得有些畸形。我开始使用碎片化的时间去看一些前端知识小短文（掘金等），面对一些可能有点争议的观点我也没有时间去钻研，看到一些来源不明的文章有时也懒得去鉴别是否正确。日语学习方面感觉更是一塌糊涂，已经完全沦为钻石等级的奴隶，每天打卡只为了留在钻石等级。背单词也是打卡后草草下场。寻求突破也许这只是职场对于我这种小白的第一个考验：如何平衡工作与生活。职场试图叫我跳出学生时代的舒适圈，既然我已经意识到了，那就该找到突破口来度过这个考验。在某些地方可能我会做出让步，但更多的方面我希望找到适合自己的方式来平衡、充实、丰富自己的生活。

稻妻之旅
type: item
date: 2025-03-23T23:23:00+08:00
description: 在大学的尾声，终于有机会以毕业旅行的名义去了一趟日本游玩。本想在回国后就写一些文字记录一下，但临近毕业的疯狂还是没能让我拿出键盘。直到工作后在几个加班的夜晚，总能回想起当时的一些趣事，便觉得还是有必要将这10天的短暂时光稍微记录一下。不得不说，这一次的旅行真的是充满幸运，且听我娓娓道来。这篇文章的诞生可以说是几经周折。本来想写一篇事无巨细的记录性游记，写到 4000 字（约 30% 进度）左右的时候因为一次操作失误导致草稿丢失了。可能我的流水账文章让博客之神感到不满，所以把我的稿件退回了。既然如此我也不花过多笔墨去介绍一些细枝末节的小细节了。10 天的冒险在 2024.5.27 日，我与朋友小 Y 从深圳出发。旅途按照地区主要分为三个部分东京（3 天）东京周边：镰仓、富士山（2 天）关西：大阪、京都（3 天）一帆风顺の东京东京是我们此行的第一个目的地，我们的存档点（酒店）订在了比较便利的池袋。距离宇宙中心新宿只用 4 站电车。只要到了新宿之后一切交通问题都可以迎刃而解。而潮流中心涩谷距离新宿也只需要 2 站。不过银座等东京 CBD 地段就稍远一些了。经过规划，我们的游玩顺序也是由近至远。DAY 1第一天属于新宿与涩谷这两个双子星。上午逛了下新宿御苑，感受了下日本的皇家庭园。由于没有什么艺术细菌，只是走马观花一般地逛了一圈。倒是小 Y 突然想起来言叶之庭里好像有这个新宿御苑的戏份，于是又屁颠屁颠地去打了个卡。（其实也不知道是不是那个地方）[photos]新宿御苑,https://cdn.exia.xyz/img/blog/632/IMG_20240530_113440.jpg|疑似打卡点,https://cdn.exia.xyz/img/blog/632/IMG_20240530_114208.jpg[/photos]吃过午饭后我们便开始了街溜子之旅，一路从新宿逛到涩谷（并非徒步）。作为两个对潮流元素不那么感兴趣的小伙子，新宿与涉谷纯粹是来打打卡、见见世面，逛的最多的还是各种中古店。[photos]波奇酱,https://cdn.exia.xyz/img/blog/632/IMG_20240530_144036.jpg|M 记自拍,https://cdn.exia.xyz/img/blog/632/IMG_20240530_145355.jpg|白天还没什么人的歌舞伎一番街,https://cdn.exia.xyz/img/blog/632/IMG_20240530_151425.jpg|传说中的十字路口,https://cdn.exia.xyz/img/blog/632/IMG_20240530_155901.jpg[/photos]DAY 2第二天我们直奔二次元圣地秋叶原进行一个朝圣。从电车站一出来就能看到在命运石之门中经常出现的场景：车站本身以及ラジオ会館[photos]车站大门,https://cdn.exia.xyz/img/blog/632/IMG_20240531_105507.jpg|收音机会馆说是,https://cdn.exia.xyz/img/blog/632/IMG_20240531_105713.jpg[/photos]说到二次元，我也只能算是追追番，闲的时候玩玩二游。但是也只到此为止了，没有疯狂地吃谷、没有成堆的手办山，更没有魔怔的精神状态。可以说是一个精神健康且心智健全的阳光小伙。不过这也和我的生长环境脱不了关系，从小生活在二次元氛围并不浓郁的深圳。听去了广州念大学的同学说，当地几个高中的 ACG 社团还会联合举办活动，更是有着远近闻名的萤火虫漫展。在某次机缘巧合下被该同学拐去了大名鼎鼎的动漫星城，狠狠刷新了我对老广的二次元浓度的认知。从那之后我也更加期待本次的秋叶原之旅。[photos]经常在网图中出现的场景,https://cdn.exia.xyz/img/blog/632/IMG_20240531_150336.jpg|走出国门的米哈游,https://cdn.exia.xyz/img/blog/632/IMG_20240531_111446.jpg|二手书店中的专业书籍,https://cdn.exia.xyz/img/blog/632/IMG_20240531_154844.jpg[/photos]逛完一天下来，可以感受到秋叶原的二次元气息与国内有所不同。国内的二次元文化的氛围其实已经非常优秀了，广泛的受众与愈发成熟的商业模式能够支持其国内二次元的快速发展。日本作为发源地，更像是将二次元文化融入了生活，在秋叶原看到的从业者们大多数都是真心热爱并且对二次元文化了解也比较深。国内由于发展速度比较迅猛、市场也日益壮大，不少看到机会的圈外人也进来发展。所以在国内有时能看到一些看似精美实则牛头不对马…

博客拔草记录
type: item
date: 2024-04-15T23:53:40+08:00
description: 自从2022下半年去腾讯实习后，就好久没有对博客进行过维护了。虽然有时会心血来潮迁移博客到更“好”的节点，结果却导致了更多问题出现。神经大条的我终于在这两天发现了一些端倪，这才动手处理了一下。虽然自认为对 typecho 这个系统已经足够了解，但是遇到问题排查起来还是满头大汗。下面是本次拔草发现的所有问题。访问奇慢无比评论大概率失败评论邮件通知不翼而飞各类数据库表问题层出不穷这是从哪里冒出来的冒充动态博客的静态网站吗？在发现了相关问题后，我便着手开始对我这菠萝菠萝的博客进行抢救了。下面是部分原因分析与处理方案👇🏻访问速度慢之前自己琢磨网络架构，把数据库都集中到了一个服务器节点统一管理。其他子系统则是通过远程连接来访问数据库。当前博客所在的服务器与数据库服务器的连接速度简直堪忧。导致 typecho 从数据库拉取数据花费的时间都非常长。当 typecho 终于渲染出页面传给用户浏览器后，等得不耐烦的浏览器又遇到了两只拦路虎：两张大小分别为 16.4mb 和 9.6mb 的图片。这两张图片在消耗流量的同时相比也消耗了不少游客的心智。虽然不知道我当时为什么要设置这么大的背景图片和头图，但是我这么做一定有我自己的道理吧！最后将博客与数据库放在了同一台服务器上并把图片换成了普通大小后，博客的访问速度也算是恢复了正常水平。评论大概率失败评论相关问题则是由各类插件与数据库连接异常引起的。在一条评论从游客的浏览器发出后，它需要经过以下两个插件的把守才可以抵达数据库SmartSpam 反垃圾评论插件CommentToMail 邮件提醒插件首先是犯下傲慢之罪的反垃圾评论插件，仗着自己是管理员信任的第一大关，掌管一条评论是通往垃圾箱还是数据库的生死大权，便为所欲为。在测试中反垃圾评论插件经常发生各种误判情况，明明是不包含敏感词的正常评论内容，却被标记为垃圾评论；明明是一个普通的游客邮箱，却提示被管理员屏蔽。工作态度之差劲令人瞠目结舌，简直难堪大用。其次是犯下其次之罪的邮件提醒插件，工作中更是充满各种虚报误报。理想情况下在激活插件时，它会在服务器中建立一个表，用于记录评论邮件发送状态，在每次评论时都去更新表的数据。实际情况是在激活插件时，它 try 了一下在数据库中建表，并没有成功。于是他做出了一个违背祖宗的决定，隐瞒建表失败的事实，上书禀报建表一切顺利。最后在实际评论时露出了马脚。这也导致了评论通知邮件的不翼而飞。鉴于这两位的工作表现与工作态度，我决定奖励它们永久假期。邮件提示插件也换成了 ethanzhao2001/Mailer-Typecho。真实情况可能是 typecho 更新后，老版本插件的兼容性问题。以及迁移博客后，没有正确设置文件权限的问题。其他在拔草之余，我也访问了一下友链中的朋友们。看到了不少朋友的近况，也看到不少朋友的博客也渐渐停止了更新。甚至有很多已经无法访问。虽然博客的逝去已经是必然的趋势，但是当离别真正来临还是免不了落泪。在这次访问中发现下面的这些博客已经无法访问了，便将他们暂时放到了友链页面的失效折叠列表中。如果后续有恢复的话，欢迎联系我添加回来。暮去长空海了个螺小凡梦WitheredstarMZRME‘S石青舟Funix's blog东马的白色相簿Y2Nk4Troy的星球南蛰的藤球球metheno小代理の记事簿客栈一新梦游计

2023年终总结
type: item
date: 2024-01-29T23:37:00+08:00
description: 2023年对我来说是毫无疑问的丰收年。今年有了太多突破与成长，做了很多从未做过的事，也向着更好的自己迈出了一大步。今年做了什么“闭门造车”的上半年在23年的年初，我开始学习一些前后端新技术，尝试了很多新的技术栈。在前端，印象比较深刻的有ValtioTailwindcssReact Query (Tanstack/Query)这也代表了前端比较重要的3个方面：状态管理、样式、请求。在这其中也尝试了不少其他同类的相关工具，比如状态管理还玩了玩Jotai, zustand等。请求库这边也试了试ahook的useRequest和alova等。样式这边也是鼓捣了不少组件库与插件。后端这边主要是学习了一些基础的东西，比如SequelizeExpressMongoDBRedis主要是一些后端框架和数据库相关。但是光是敲一些简单的例子感觉还是不太够，于是想起了我高中走神时琢磨的一些个人网络的构想。以一个SSO为中心建立起一套完善的应用系统，基础形态包含如下组件。SSO动态配置系统 - 用于接入到其他组件提供动态配置能力消息系统 - 实现多渠道的通知能力（邮件，短信...）服务器状态管理 - 类似于探针一类的东西重构博客各种小应用...虽然做出来大概率就是自己一个人用，根本犯不上这么复杂，但还是忍不住动手开始敲了。吭哧吭哧边学边敲，敲了三四个月，总算是把基础的SSO和动态配置系统肝出来了。这期间除了从技术的角度研究，也不断尝试用产品的角度去思考怎么样才能让我的0 IP应用变得相对更好用一些，也算是有了不少的收获。秋招小子大三下学期，计算机专业的带学生不可避免地迎来残酷的秋招。回想起我的秋招经历，做了许多努力，也做了许多错误的决定。6~10月的这段时间里，大多数时间都在埋头看技术相关书籍，刷算法题，试着慢慢完善我的知识体系。但事与愿违，我的努力并没有收到相应的成效，因为我做了一个错误的决定。与其他秋招小子不同，我没有去看八股文，而是回到红宝书等相关理论书籍中去细嚼慢咽。单从行为本身来看，这是一个比较好的做法，能够更加夯实地建设起我的知识体系。但结合实际情况，在秋招这种时间有限的情况下再回头去抱着书啃无疑是个“错误”的选择。在时间有限的情况下，我更需要的是一个相对来说短期收益明显的方式来快速提升我的纸面实力。我却选择了需要投入大量时间的长效投资。在一次美团的面试后，我认识到了自己的错误。我被面试官从头拷打到尾，把我知识体系刚刚夯实的地基砸了个大洞，往下一探，发现塞满了棉花。我看着面试官从刚开始面试时的兴致勃勃到最后失望离场，心里满是说不上来的滋味。知识无分贵贱，而当时心高气傲的我却不明白这个道理。八股并不是什么上不了台面的东西，相反他是很多工作中积累下来的经验的浓缩。在那场面试后，我也开始找八股，看八股，但是一直找不到面试的感觉了。双非学生收到的寥寥一次面试邀请也大多数停留在了二面阶段。打工/转正小子从22年10月底到23年结束，我也已经在鹅厂干了一年多了。在这里遇到了非常好的导师和同事，也接触到了很多象牙塔里接触不到的事情。在7月初，我被通知有转正的机会。在8月30号迎来了我的转正答辩。当时其实对于转正并不是抱有很大的期待，毕竟同组还有两个研究生。答辩基本上也是当成在腾讯实习的最后一舞来准备了。没想到的是在9月中旬，我收到了我转正通过的信息，接下来便是接意向，签OFFER，谈薪资。在11月，我的鹅厂身份也从实习生变成了毕业生。本来计划的故意弄丢一张工卡挂失留作纪念工卡也可以晚几年再实施了。减肥小子最有成就感的一集在年初时的某一次上称，发现自己喜提82.6公斤并获得了肥仔头衔。高中的我体重一直维持在77公斤上下，看起来已经是有点小胖了。这82.6放在高中是我想都不敢想的数字。痛定思痛后的我开始了我的减肥计划。一开始的计划是通过减少食量轻松减肥，少吃到五六月份发现减得并不是很肥。体重一直卡在80公斤动弹不得。于是6月变开启了我的跑步之旅。[photos]体重,https://cdn.exia.xyz/img/blog/630/image-20240128235734776.png|相关数据,https://cdn.exia.xyz/img/blog/630/image-20240128235832737.png|[/photos]深圳的天气比较热，一开始的时候是隔天跑，每次4km，但是时不时会偷懒不去。但是当我又是某次上称时，看到许久没有变化的体重开始出现轻微下滑时，我开始激发我的小宇宙了。我开始慢慢坚持全勤打卡，每个月尽量跑满15次。天气转凉后开始提升公里数，4km和6km交替打卡。每个月的跑量也在不断提升。5月6月7月8月9月10月11月12月35.54km51.05km72.4km75km65.32km91.56km77.27km87.58km…

使用 React Query 优化请求！
type: item
date: 2023-06-19T00:14:00+08:00
description: 很早之前就看到 React Query 在前端掘金圈子里火了一把，一直想学却因为种种原因没有开始。这一阵子闲下来了一些，快速学习了一下并且在自己的小项目里上手用了一番，体验非常不错。所以在这里以 React Query 为例写一篇 TanStack Query 小小的快速上手指南。React QueryTanStack Query (FKA React Query) is often described as the missing data-fetching library for web applications, but in more technical terms, it makes fetching, caching, synchronizing and updating server state in your web applications a breeze.TanStack Query（前称 React Query，在下文中我们也采用这个称呼）通常被形容为 Web 应用所缺失的数据请求库。更专业的说法是，他让你的 web 应用中的请求、缓存、同步与更新服务端状态更加轻而易举了。从我这段时间的使用体验来看，其中对于请求与缓存的处理可以说是 React Query 给我带来的最显著的提升。以这样一段请求为例👇🏻function getListData() { return axios.get('https://xxxx'); } function List() { // 数据 const [data, setData] = useState([]) // 加载状态 const [loading, setLoading] = useState(false) // ... const queryData = () => { setLoading(true) getListData().then((res) => { // ... setData(res.data.data) }).catch((error) => { // ... }).finally(() => { setLoading(false) }) } useEffect(() => { // 满足某种条件才请求 if (fulfilled) { queryData(); } }, []) // ... // return template; }使用 React Query 管理请求后，我们可以这样写（用过 ahooks 的 useRequest 的小伙伴应该很熟悉这种写法）function List() { // ... const { data, isFetching } = useQuery({ queryFn: getListData, // 查询函数 queryKey: ["list", "query"], // 查询键 enabled: fulfilled, // 是否启用 }); // ... // return template; }在外层，我们需要创建一个 QueryClient 并使用 QueryClientProvider 来提供一个查询的上下文。const queryClient = new QueryClient() function App() { return ( <QueryClientProvider client={queryClient}> <Todos /> </QueryClientProvider> ) }我们把冗长的请求逻辑全部都交由 React Query 来帮我们处理，我们只需要关心请求的状态和数据即可。更详细一些让我们聚焦在例子中 useQuery 这个方法上const { data, isFetching } = useQuery({ queryFn: getListData, // 查询函数 queryKey: ["list", "query"], // 查询键 enabled: fulfilled, // 是否启用 });入参对于入参，这里我们就需要介绍一下 React Query 中最关键的两个参数：queryFn 和 queryKey。查询函数（queryFn）需要是能够返回 Promise 的任意函数。而该 Promise 的返回值将会被填充至 useQuery 返回的 结果数据 data 或是 错误 error 。查询键（queryKey）需要是一个数组，其元素可以是任何可以被序列化的类型。当然， React作为一个开箱即用的库，其本身还包含着一些默认配置。如果你发现 Devtool 的网络 tab 中时不时冒出来一个预期意外的请求。不要着急提Bug，这可能是以下几个默认开启的配置项在“搞…

踩了个嵌套滚动的坑
type: item
date: 2023-02-25T23:35:00+08:00
description: 问题引出考虑如下场景：一个菜单，限高可滚动；其中每一个元素又可以在侧边展开为小菜单，小菜单也同样限高可滚动主流的思路应该是利用大部分组件库都有的 Popup 浮层（我猜的但是如果你的子菜单弹出层是父菜单的元素的子元素，子菜单是靠父菜单的元素 hover 唤出的。比如这样👇🏻 {{ i }} {{ j }} 我的第一直觉告诉我，这不就是一个 overflow 的问题吗？我直接使其在 y 轴上自由滚动，x 轴上也无遮无挡。overflow-y: auto; overflow-x: visible;实际情况是，刷新完页面，清完缓存，再刷再清后，不论我怎么hover，子菜单都弹不出来。最后检查了一下控制台的 computed 属性，发现我的 overflow-x: visible 已经被浏览器偷偷换成了 overflow: auto为什么明明我写的是 visible ，浏览器却解释成 auto 了呢？再尝试将y轴设为 hidden ， x 轴保持 visible 。发现浏览器依然将 x 轴解释成了 auto 。浏览器：“你弹子菜单出来，可以，但是不能滚动；你要滚动，可以，但是不能弹子菜单出来。”问题出现简单翻阅资料后在 sof 发现了想要的回答，有个老哥引用了一段 W3C 规范，原文如下The computed values of ‘overflow-x’ and ‘overflow-y’ are the same as their specified values, except that some combinations with ‘visible’ are not possible: if one is specified as ‘visible’ and the other is ‘scroll’ or ‘auto’, then ‘visible’ is set to ‘auto’. The computed value of ‘overflow’ is equal to the computed value of ‘overflow-x’ if ‘overflow-y’ is the same; otherwise it is the pair of computed values of ‘overflow-x’ and ‘overflow-y’.看到这里顿时茅塞顿开，原来这是 W3C规定的，并不是其他问题导致的无法实现。但是为什么要这样子规定呢？这一层回答下面也有很多感到不解的回复仔细一看，回答是在2011年的，下面几个相关评论也直到17/18年左右，有没有可能已经 W3C 更新了呢？（明显没有，要是更新了不就没有那么多问题了）点开老哥引用的 W3C 链接，发现确实更新了，overflow 属性已经不在那篇文档里了，又稍微找了找，发现了更新的两篇关于 overflow 的草稿https://www.w3.org/TR/2022/WD-css-overflow-3-20221231/https://www.w3.org/TR/2022/WD-css-overflow-4-20221231/在CSS3的草稿中摸了半天，看到了这么一句话The visible/clip values of overflow compute to auto/hidden (respectively) if one of overflow-x or overflow-y is neither visible nor clip.虽然没看到为什么要这样调整，但是W3C这么做一定有他的道理（确信。既然如此，我们只能另辟蹊径了。尝试解决说是另辟蹊径，但是想了半天也没得思路。这个时候我的导师给我支了一招：“你可以试试用 transform 模拟滚动”。这可真是醍醐灌顶的当头一棒。浏览器不给咱们滚，咱们可以用自己滚！监听目标的 WheelEvent 来获得鼠标滚动的 deltaY 的值，通过对应修改容器的 transform ，妙啊！说时迟那时快，一顿操作后简单实现了一下这个想法，同时也发现了一些问题。滚动方向问题：Mac 和 windows 的滚动方向不一致，甚至有些情况下触控板和鼠标的滚动都是不一致的。需要计算滚动的边界问题（避免滚出去滚不回来）子菜单的滚轮滚动也会被监听，导致整个菜单一起滚动层级问题：向上滚动时会遮挡上方同层级的元素...就当我准备把这些难关一一攻克的时候，想起导师说的一句话：“咱们遇到的问题肯定有人都踩过坑，可以去找找有没有现成的库”。关键词：transform + scroll + js搜索结果：ustbhuangyi/better-scroll虽然他是通过鼠标拖拽来实现的滚动，但是配合他的 mouse-wheel 插件也可以实现鼠标…

2022年终总结
type: item
date: 2023-01-21T18:04:00+08:00
description: 2022年马上就要过去了，相信今年有很多令大家难忘的回忆。我也接着这篇年终总结记录一下我的2022年。我可以把我的2022年按照时间顺序大致分为三个阶段找工作找到工作迷失找工作22年年初，不知道看到了今年互联网就业形势可能会很差的消息。虽然当时春招也只是出现端倪，但是当时大家相对来说没太放在心上，认为只是疫情带来的轻微波动罢了。由于我们学校在大三下需要去企业实习，如果不满足于与学校合作的企业提供的就业岗位，那么就需要自己去找实习。所以这也让没怎么关注就业形势的我开始在这方面上了一些心。我自认为基础很差，所有的功夫只是浮于表面，对自己在找实习这方面并不是很有信心。在看到这则消息后便开始了疯狂的学习。从年初到六七月份，我在JS基础和算法方面花了比较多的功夫。《红宝书》、《你不知道的JS》等更是翻了又翻。算法方面有工作室的Uni学长带路，相对于我原本孱弱的算法能力也是有了长足进步，终于勉强达到了面试者的平均水平（当我冒出来这个想法的时候我就知道可能还没有期间我通过Uni学长的内推尝试面了一下字节飞书。问答环节一切都好，但是无奈手写题的时候还是犯了写算法题时常犯的错误——没读清题就下手。导致这一次面试也是以失败告终。到了8月份，我又参加了学校与腾讯合作的一个暑期项目实践。在这里又接触到了很多优秀的同学和导师。关于这一部分可以看看这篇博客~[art]624[/art]项目实践后，我又去请教了一下在腾讯实习的学长关于找实习方面的问题。在问及该什么时候开始投递简历面试的时候，学长的答复是：“你可以现在就开始了”。于是又在Boss直聘等软件碰壁了两个月之后，终于在腾讯找到了人生第一份实习。找到工作在腾讯工作的日子真的非常充实。每天基本上从9点半开始敲，敲到12点恰个饭睡个觉。下午两点再开始敲，敲到6点再恰个饭，吃饭完回来接着敲。原本快要生锈的脑袋也在这种环境下慢慢转了起来，经常由于脑袋消耗过多能量导致饭点前两个钟就开始肚子咕咕叫。IEG也真的成了挨饿🐔（bushi不过好在在身边都是dalao的情况下，对于各种能力的培养也非常快（自我感觉。经常能get到一些非常好用的技巧或者写法。对于软技能方面又有所提升（除了自我表达能力其他的更多可以看看这里[art]626[/art]迷失在入职了将近一个月后，终于算是找到了实习的节奏。平时自己自由支配的时间也慢慢多了起来，但是人的惰性也如期而至。从之前的学习经验来说，最重要的还是学习中沉淀的过程。在前一个月，由于还没适应工作节奏，导致了很多无故加班，回到家洗洗差不多就可以睡了，没什么时间沉淀自己。除此之外，我也不想这一次实习只是一次实习，谁不想留在大厂上班呢。但是大厂的转正留用考核又哪有那么简单，加之我的潜在竞争者基本上都是名校研究生，感觉又是难上加难。在前方有着上面说的两堵大墙的情况下，我也第一次拿到了自己的工资。这笔工资对于我来说，真的是打开了很多以前没有打开过的大门。对于一个算是刚刚步入社会的学生仔来说，真的像是打开了潘多拉的盒子。我突然发现有趣的东西有很多，这里可以试试，那里可以玩玩。在这一段时间里，我曾经拥有很多短暂的爱好。实际上却都是泡沫，除了浪费掉我的时间意外并没有什么实质性的价值。这一段时间也许可以用黑暗来形容。我自我安慰自己说我一个21世纪的大学生，花点这些钱不是也很正常吗？可能正常，但是真的合适吗？总结总结来说我个人认为2022年我最大收获有两点：一是心性的转变，从学生变成了打工人。很多时候不会再像学生那样去思考问题了；二是完成了一段相对圆满的追梦之旅，找到了一份大厂的实习。也可以说是自己的能力得到了一定的肯定吧。同时也在很多方面暴露出了问题，希望能2023年找到解决方案。拜托了，2023年的我。加油啊，2023年的我。

写在入职🐧两周后
type: item
date: 2022-11-13T23:20:00+08:00
description: 今天是入职腾讯后的第18天，上周五的时候终于结束了第一个需求，也终于有时间来总结一下过去这一两个月从面试到入职到现在的一些经历。敲一敲鹅厂的大门🚪作为应用型技术大学，深技大有个特色：每个同学大三下半学期都需要去到企业实习。我自然也逃不了大三下的社畜体验券。但是自从2022年开始，互联网的寒气似乎在慢慢扩散开来，身边几个原本一起学习前端的同学也润考研了，加上一些在大厂的学长都说不容易，我也渐渐开始紧张起来。虽然说不是要第一份工作就一定要找大厂，但毕竟求其上者得其中，求其中者得其下，还是希望能对自己要求高一点，多尝试，多感受。给自己订的计划是先从中小厂开始练手，锻炼一下自己的面试能力，再去以更好的状态尝试大厂。但是现实并没有想象的那么美好，在Boss直聘等平台沟通了一些比较心动的中小厂，得到的都统一回复：暂时不招24届的哦。四处碰壁后也有些疲惫了，开始佛系起来。直到9月初在CSIG的学长找到我，问我想不想去试一下。一拍大腿，冲了！从9.22面到10.8，最后10.17收到OFFER，约了在10.27入职。鹅厂的生活从需求开始📔在正式入职之前，从隔壁组的学长和我们组组长的言语里都能感受到那边是真的着急用人，自己心里也做好了到岗立马干活的准备。但是没想到的是，我们组似乎比我预想的还要忙。入职第一天上午，办公用的笔记本还没有配到，导师已经跟我介绍起了需求和需要用到的相关技术栈。下午电脑送到，系统配好，晚上就开始跑起项目看代码了。我的腾讯社畜生活也就此拉开序幕。工作氛围真不错👍好的工作氛围我认为主要体现在两个方面：轻松的人际关系和高效的工作模式。在这两周，我感受到了很多在大厂工作的魅力。首先，同事间的关系非常轻松和睦，组长和组员们都是打成一团。大家对我和我同学两位新人也非常包容，会对我们进行一些指导。其次，工作的时间也非常弹性，大家可以非常自由地调整的工作时间。平时大家在工位上的时候，都非常专注，休息的时候，大家也很放松。最后一点是一个相对具体一点的细节，但是对我来说是感受比较深的。同事们在沟通中的效率都很高，很多时候提出问题或者方案，他们都可以非常清晰明确地进行描述，降低了很多沟通成本。另一个方面，工作中难免有讨论，有激烈的讨论，但是同事们大多都是第一性原理的有力执行者。不论讨论的多激烈，仔细听就会发现，其实都是在非常客观地去表达自己的观点，阐述自己的想法，而不是伴随着一些情绪。综合这几点，我感觉这一次在腾讯的实习我一定会受益良多。我的感受👦我是慢热型选手，接触新东西的时候经常需要花一些时间去消化整理（脑内构建索引）。一入职就开始写需求导致了很多问题。为了完成任务，我几乎没有什么时间去了解公司的环境，公司的各种系统用起来也磕磕绊绊。而且项目非常庞大，我花了非常多时间去捋清代码。更重要的是我很少有时间去沉淀一些知识和经验。当然，一上来就真刀真枪也是有好处的。需求ddl的压力显著加速了我这慢热型选手蜗牛般的适应速度。我明显感觉到我对项目代码的熟悉速度是最快的一次。而且工作中难免会与很多同事对接、打交道，照往常我可能要慢慢地去融入开发团队。但是这一次，从导师带着我去和别人对接到自己有问题去找相关同事对齐，无形中我也更加迅速地融入了团队。说到底还是挣脱舒适圈过程中的阵痛期吧。对自己的期待💪两周过后，真的能感受到这次实习是肯定不虚此行。那就在这里给自己定下一些小目标吧学会高效沟通学会快速适应在自己的专业领域能够有所成长这几个目标说大不大说小不小，但是真实希望自己可以在明年结束实习之前能够在这些方面有所提升。加油！

深入理解现代浏览器 阅读笔记五
type: item
date: 2022-09-11T22:35:53+08:00
description: 在上一篇博客中，我们了解了浏览器如何将开发者编写的 HTML、CSS 和 Javascript 转化成最终显示在用户屏幕上的画面。在这一过程中，我们认识到了光栅化以及合成器线程，而今天的这篇博客也与其有着密不可分的关联。输入事件（input events）从用户的视角来看，可能输入时间就是那些点击、输入或者拖动。但是从浏览器的角度来看，用户的一切动作都可以看作是输入事件，例如鼠标滚轮滚动和鼠标悬停。浏览器进程是首先捕捉到用户的输入事件的，但是浏览器只是知道用户进行了这样的一个操作，如何对用户的操作进行反应还是会交由渲染器进程处理。浏览器进程将用户的输入事件经过合成线程传递给渲染器进程，包括事件的类型（如 touchstart）和坐标，由渲染器主线程和合成线程相互配合完成对事件的响应。那么问题来了，渲染器进程是如何通过这个坐标和事件类型来判断用户到底在哪个元素交互，想要触发什么动作呢？处理输入事件细心的朋友可能发现了，在上一篇博客里面最后其实也涉及到了一些简单的输入书简处理的问题。用户滚动鼠标滚轮，合成器线程生成一个个合成帧最终渲染到屏幕上，这就是最基础的输入事件处理。在上篇博客的简单例子中，没有什么对于滚动的监听函数，合成器线程可以独立地完成这一次事件的处理。当页面变得复杂，合成器线程和渲染器主线程的配合才得以体现。两者配合的大致过程如下：浏览器进程接收到输入事件，将其坐标和事件类型传递给合成器线程后，合成器线程判断输入事件是否会触发监听回调，如果会触发就通知渲染器主线程去执行相应的 Js 函数，等到Js执行完后再去生成合成帧；如果不会触发，那么就和上面的滚动一样了，合成器不需要通知主线程，自己就可以直接渲染出一个合成帧丢给GPU。聪明的合成器在这个过程中，合成器如何快速判断点击到的位置是否包含有监听器呢？首先排除每一次都从DOM树上找的方案。chrome的开发者们找出了一个非常高效的方法，为每一次合成出来的页面打上记号，通过记号来快速判断。具体来说，合成器在合成当前的页面后，会对每一个包含挂载有事件监听器的元素的区域打上一个 non-fast scrollable region 的记号。这是直接对与区域的标记，如果点击的位置不属于被标记的范围，那合成器直接自己去合成新合成帧就可以了。如果在标记的区域内，那就需要再等等 Js 的执行了。辛苦的主线程假如点击到了带有事件监听器的区域，合成线程将事件传递给了主线程。主线程在拜托 Js 执行回调函数之前，还需要先找到用户到底是在和那一个元素交互。主线程可不像合成器线程一样能走走捷径，为了准确找到目标元素，它需要先进行一次 hit test。所谓的 hit test 其实就是在渲染过程中生成的 paint records 里去找到该事件点击的坐标上的绘制顺序，最后找到被交互的目标元素。最终，找到了目标元素的渲染器主线程将各种信息（坐标、目标元素、事件类型）等打包成我们熟知的 event 对象传递给开发者定义的回调函数去执行。如果执行的过程中改变了DOM，合成器继续等，等到重新渲染出新的 Layout tree 和 paint records 来合成新的合成帧。如果没有改变DOM，那就直接渲染就好啦。事件合成在之前的博客中，我们讨论过为了让用户有更加流畅的观感，以普通的显示为例，浏览器每秒交错刷新60次。但是对于输入事件来说，一般的触屏设备每秒可以分发60～120次的触摸事件，一般的鼠标可以分发100次左右的事件。可以看得出来，用户输入的事件的频率是远超我们的屏幕刷新次数的。考虑一个类似 touchmove 的持续输入事件，浏览器如果不经任何处理，每秒可以将差不多120个事件塞到渲染器主线程去进行一次又一次的 hit test，这远远超出了屏幕刷新的速度。想到这里，可能有些经验老道的朋友就想到了，我们可以利用节流来限制呀。就像例如点赞等一些经典场景，如果前端一监听到有人按下点赞按钮就向后端发送请求，如果碰上一群手速怪人，服务器可不好受。前端工程师为了防止服务器被这些人 gank，就心生一计，把一段时间内的点赞合成一个请求发出去，就算用户点得再快，也不过是按照我们预设的频率请求。浏览器工程师直呼“英雄所见略同”。为了让渲染器进程不会被用户随便轻轻一拉就冲垮，他们将一段连续的事件合并到一起发送给渲染器进程。当我们不太关注用户手指滑动的路径的时候，其实在一段时间内的滑动最主要位置的也就是起点和终点的坐标。通过合并这一操作，渲染器进程处理用户输入就变得相对游刃有余了。在优化后，我们可以发现合并后的时间派发给渲染器进程的时间点都在下一次 requestAnimationFrame 之前，确保能在之后执行的 Js 中获取到。一般来说只有那些连续的事件会被合并，例如 wheel, mousewheel…