<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[林深时见雾]]></title><description><![CDATA[山不让尘，川不辞盈]]></description><link>https://linmoe.cn</link><image><url>https://linmoe.cn/innei.svg</url><title>林深时见雾</title><link>https://linmoe.cn</link></image><generator>Shiro (https://github.com/Innei/Shiro)</generator><lastBuildDate>Thu, 02 Apr 2026 22:42:06 GMT</lastBuildDate><atom:link href="https://linmoe.cn/feed" rel="self" type="application/rss+xml"/><pubDate>Thu, 02 Apr 2026 22:42:06 GMT</pubDate><language><![CDATA[zh-CN]]></language><item><title><![CDATA[四年非梦：秋招总结]]></title><description><![CDATA[<link rel="preload" as="image" href="https://s41.ax1x.com/2025/12/09/pZu1YEF.jpg"/><div><blockquote>该渲染由 Shiro API 生成，可能存在排版问题，最佳体验请前往：<a href="https://linmoe.cn/posts/essay/years_summarize">https://linmoe.cn/posts/essay/years_summarize</a></blockquote><div><h2 id="1-">1. 何为校招</h2><p>​    对大厂而言，招聘通常分为校招和社招两条路径。二者最大的差异在于目标群体不同：校招面向应届生，社招面向已有经验的社会人才。因此，考察重点自然也不同。</p><p>​    社招更强调技术能力，因为社招岗位往往是项目紧急、团队缺人，需要找能“即插即用”的人；而校招生普遍缺乏实战经验，面试官默认是一张白纸，因此校招更侧重考察“潜力”。</p><p>​    那么，潜力从哪体现？最重要的筛选工具，就是学历。</p><p>​    在我国，高考是最公平、最规范、官方背书的选拔机制，它在某种意义上代表了一个人在长期学习体系中的执行力、学习能力和稳定性。企业用学历筛选，本质上是为了降低招聘成本——技术可以培养，但学历无法后补。</p><h2 id="2-">2. 影响校招的主要因素</h2><p>​    从技术岗来讲，无非运气，学历，实习，项目。运气就不谈了，学历整体上可以分为 92 与 双非，不乏有公司/部门会卡双一流（就互联网而言）。如果给这四个因素排序，我的答案是：<strong>运气 &gt; 学历 &gt;&gt; 实习 &gt; 项目</strong></p><p>​    有人可能会说，大厂实习的含金量不应该大于学历吗？或许在实习阶段你能拿到很多的offer，但实习和校招是完全不同的，实习做的内容大概都是杂活，一个实习生能待的时间也就是6个月左右，但校招生不同，对于面试官而言，一面面试官是你的同事，他招的是未来一起工作的战友；对你的二面面试官而言，他招的是未来能冲锋陷阵的士兵。或许学历不能代表一切，但至少能代表在高中三年期间你完美的执行了学校老师布置的任务，并在高考中交出一份完美的答卷。所以，大厂实习只能一定程度上去弥补你和 92 之间的差距。更多时候，你的竞争对手是双非。</p><p>​    我见过二本一段大厂拿下阿里淘天（卡学历），美团和腾讯的，也见过双非三段大厂秋招颗粒无收的，更见过九本一段小厂秋招打牌的。但这并非代表你所做的努力是没有意义的，我相信世界上没有白走的路。</p><h2 id="3-">3. 校招的变化趋势</h2><p>​    就前后端而言，市场变化是很快的，但总体趋势是下降，去年25届前端校招还是可以的，只是一年的时间，26届前端就开始全面崩盘。以今年来看，我总结了几个明显的变化：</p><h3 id="31-ai">3.1 AI的快速发展</h3><p>​    25年可以说是 AI 爆发最快的一年，也可以说是 Agent 元年，各种新理念新技术层出不穷，前几年虽然一直在喊前端已死，但只有今年让我切切实实的嗅到了危机感。AI的发展是否会使前端消失？答案是不可能的，十几年前的PHP至今都依然有人在写，不过前端的需求必然是会减少的，中小厂的前端 HC 会进一步减少，甚至小厂会取消前端这个岗位，大厂的前端需求短时间可能会增长停滞，但影响不会太大。不过我觉得大厂业务停滞增长，本身也是一种退后了。</p><div style="display:flex;gap:16px"><img src="https://s41.ax1x.com/2025/12/09/pZu1YEF.jpg" alt="图1"/></div><h3 id="32-">3.2 大厂实习贬值</h3><p>​    好像是从24届还是25届开始，我明显感觉市面上的大厂实习岗位开始增多，尤其是字节和美团，日常实习基本上一年四季在招，从今年周围朋友情况来看，2-3段大厂实习的不再少数，所谓物以稀为贵，当人人都有大厂实习的情况下，大厂实习就会贬值没有含金量，我也问过几个27届的学弟，几乎都在大二下就有两段实习，可见卷实习的浪潮只会愈演愈烈，而公司也乐于看到这种结果，一方面实习生的待遇相较于正式来说不算什么，甚至比外包还低，一方面应届生的质量在不断的提高，公司可以得到更优质的应届生资源，对公司来说百利无一害可以说。</p><h3 id="33-">3.3 高学历市场下沉</h3><p>​    说到双九（本硕都是985），大家的第一想法肯定是科研，算法。但就今年情况来看，很多双九硕都选择来前端，这其实是一种市场下沉的现象，从最开始的双九硕做算法，到双九硕做后端，最后甚至来做前端，我觉得这是一个很恐怖的现象，进一步证实互联网市场正在饱和。</p><p>​    说到高学历就不得不提一个特别著名的学历厂——比亚迪。在22年以前单2（本科211以上）点击就送，到24年双2（本硕211以上）点击就送，到今年双九（本硕985）点击就送。</p><p>​    这就是当下互联网的真实环境：池子变小了，加入的水却越来越多。</p><h2 id="4-">4. 规划与选择</h2><blockquote><p>时代的一粒沙，落在普通人身上，就是一座山。
既然无法改变环境，就只能改变自己。
变则生，不变则亡。</p></blockquote>
<p>​    互联网的变化速度是传统行业不能比的，在校招中规划和选择变的越来越重要，放在十年前也许你玩三年，最后拼一年就能进入一家不错的公司，但放在今天不行了，如果你的目标是进入一家中大型企业，那么你必须趁早规划并做出努力。</p><h3 id="41-">4.1 信息差</h3><p>​    计算机永远不是闭门造车。除了增强自己的技术，你还需要收集一些新的“信息”，如果你的学校是 985211 或者就业很强的学校，你的学长前辈们可能已经帮你们走出一条路，但如果你的学校不是很好，没有前人的路可以走，那就只能摸着石头过河，自己走出一条路，而 “信息差” 就是走出这条路的关键。</p><p>​    比如我想从事前后端开发，我需要学习哪些技术栈？如果我想要进入大厂实习，我该怎么写简历？我该在哪投简历？什么时候投？这些都是有技巧的，这也是计算机的一部分。</p><p>​    作为一名刚刚入校的新生我该如何打破信息差？先把眼光放在校内，是否有出名的工作室，工作室里是否有还在大厂的学长，如果没有则把注意力放在校外，我推荐使用牛客，计算机校招生的聚集地，很多人会在牛客交流经验，并且你也可以去加入一些交流群，当然这些信息很驳杂，需要自己有过滤和判断能力。</p><h3 id="42-">4.2 执行与驱动力</h3><p>​    计算机是一门永远进步的学科。你需要保持永远的学习力，对大部分计算机从业者来说，技术才是核心竞争力，你需要时刻了解行业正在发生的变化，并学习新的技术。</p><p>​    比如我想在大二暑假找到实习，那么我必须在这一个月内去学完相应的技术栈，并做出一个完整的项目，这个计划必须在规定时间内完整的执行下去。</p><h3 id="43-">4.3 选择大于努力</h3><p>​    有时候错误的选择往往会导致努力白费。如果你在25届学前端，那么恭喜你遇到了前端最好的一年；如果你在26年学前端，那么很遗憾你的对手不是985就是多段大厂实习的双非，但如果今年你学习的是测开/客户端这种市场缺口很大的岗位，那么你上岸的几率将大大提升。</p><p>​    在我的周围就有这样的例子，朋友A双非大二开始学客户端，大三下暑假进入腾讯实习，并成功转正；朋友B双非原本是学后端的，暑假收到一家中厂的后端 offer 和腾讯的客户端 offer，最后选择去腾讯客户端，同样他成功转正。</p><p>​    作为反面教材那就是我和周围认识的十一个腾讯前端，一共十二个人只有两个转正成功。</p><h2 id="5-">5. 就业与考研</h2><p>​    对本科生来说，毕业后的道路无非两条：<strong>直接就业</strong>或<strong>继续升学</strong>。</p><p>​    升学当然是一种选择，但绝不能盲目。我始终认为，做任何决定前，都必须想清楚——<strong>你会承担什么代价？你能获得什么收益？</strong></p><h3 id="51-">5.1 什么样的人适合升学</h3><p>​    <strong>只有带着明确目的的人，才适合走升学这条路。</strong></p><p>​    就以我个人为例，很多人不理解——<strong>明明本科阶段就能拿到大厂 offer，为什么还要读研？</strong> 这个问题我也反复问过自己。</p><p>​    抛开浮躁和短期收益不谈，计算机行业本质是“青春饭”，是一个永远不缺年轻人的赛道。当我意识到自己学历不占优势时，也开始思考，当职业生涯走到瓶颈，我还能靠什么翻盘？我又能凭什么在 35 岁后依然拥有选择权？</p><p>​    如果我去读研，我必然会失去三年的工作经验，以及近百万的收入，更要承受三年后市场可能继续收缩的风险。
 但升学带来的收益同样清晰：学历提升、专业转向（例如前端转后端）、甚至跳向门槛更高的国企或体制内。</p><p>​    <strong>所以适不适合升学，不在于你“能不能考上”，而在于你“为什么要考上”。</strong></p><h3 id="52-">5.2 尽量不要并行</h3><p>​    人的精力毕竟有限，<strong>试图“就业 + 考研”双线推进的人，往往两头都顾不住。</strong>尤其是对于大多数身处双非、资源有限的学生来说，不是没有天赋，而是时间与精力根本不允许你无限分散。如果你决定两手抓，那你必须先问自己两个问题：</p><ol start="1"><li><strong>你能否放弃几乎所有娱乐与社交？</strong></li><li><strong>你是否能在长达半年以上的时间里，每一天都严格执行计划，不拖延、不松懈？</strong></li></ol><p>​    不论是校招还是考研，都是极其消耗意志的过程。尤其是从九月到十二月——校招的高峰期、考研的冲刺期、心理的崩溃期。这是最接近黎明的黑暗，也是最容易被击垮的阶段。</p><p>​    如果你无法保证“双线高压”下的执行力，那么最理智的做法就是——<strong>专注做一件事，并把它做到极致。</strong></p><h2 id="6-">6. 尾声：写在最后</h2><p>​    四年前我从高中走进大学的校门，曾几何时觉得自己前途一片渺茫，和周围许多朋友相比我算不上天才，但相较于他们我的优点在于对未来必胜的决心，以及敢于一条路走到底的勇气。</p><p>​    从携程到腾讯，感恩路途中帮助过我的所有人。四年一路走来最大的收获不是拿到过的offer，而是路途中遇到的人与事物，有人令我成长，有人为我指明方向，我想未来不论是成功还是失败，我都已经做好准备去迎接了。</p><p>​    直面自己的失败，并战胜它——大学四年留给我的最后一课</p><style>p {
  text-indent: 2em;    /* 首行缩进两个字 */
  margin-bottom: 1em;  /* 段落间距 */
  line-height: 1.6;    /* 行高 */
}
</style></div><p style="text-align:right"><a href="https://linmoe.cn/posts/essay/years_summarize#comments">看完了？说点什么呢</a></p></div>]]></description><link>https://linmoe.cn/posts/essay/years_summarize</link><guid isPermaLink="true">https://linmoe.cn/posts/essay/years_summarize</guid><dc:creator><![CDATA[林陌青川]]></dc:creator><pubDate>Tue, 09 Dec 2025 09:30:48 GMT</pubDate></item><item><title><![CDATA[三年风雪，我心如初]]></title><description><![CDATA[<div><blockquote>该渲染由 Shiro API 生成，可能存在排版问题，最佳体验请前往：<a href="https://linmoe.cn/notes/7">https://linmoe.cn/notes/7</a></blockquote><div><p>​    若你现在处于低谷中，希望听完我的故事你能振作起来。</p><p>​    小时候我生活在华中地区的一个地级市。由于父母工作的原因，大约六年级时我被接去了省会，那是我第一次离开生活了十多年的故乡。</p><p>​    来到繁华的大城市，因为没有朋友，小学最后一年过得并不如意。小升初时被分配到区里一所较差的初中。初中一个年级只有四个班，我幸运地在分班考试中进入了快班。第一次期末考试我考了年级第23名。</p><p>​    后来在初一下时，我遇到了生命中第一位恩师——她是我数学的启蒙老师。也是在她的教导下，我的数学从短板一跃成为了长处。初二时我常年稳居年级前五。</p><p>​    可到了初三，因为恩师出国留学，我在最后一年没能坚守初心，成绩一落千丈，最终在中考中迎来人生第一次大败。</p><p>​    有人说，从那时起，我的命运被改变了。本能考进省重点的我，最后只进入了一所市重点。</p><p>​    进入高中后，高一的成绩不温不火。高一下学期，疫情全面爆发，我们被迫上网课。那段时间我患上了中度抑郁症，成绩也一落千丈。高中三年，是我最不愿回忆的时光。</p><p>​    如果非要说一段快乐的记忆，那应该是我第一次接触计算机的那段时间吧。高三时我拼了一把，最终考上了一所普通二本。或许，一切都是最好的安排。</p><p>​    八月份，爷爷查出癌症晚期，而我也错过了与他见最后一面的机会，这是我一生的遗憾。</p><p>​    记得小时候在老家，虽然家里清贫，但无论我想要什么，爷爷都会尽力满足。虽然父母常年不在身边，但只要有爷爷奶奶在，我从未觉得自己比别人缺少什么。</p><p>​    对爷爷来说，能看到我考上大学，也许了却了他的一桩心愿。那一晚，跪在爷爷遗体前，我发誓：我一定要尽我所能，去拼一个未来。</p><p>​    进入大学后，我开始规划自己的四年生涯。学校里的学长大多从事后端方向，即使有少数选择前端，也并未走出理想的道路。或许是因为高中时接触过前端，我在职业发展上毫不犹豫地选择了这一方向。</p><p>​    大一下学期，凭借自己的努力，我在一家小型公司获得了实习机会。那时技术水平还十分稚嫩，但热情却是最为炽烈的。</p><p>​    大二上学期的寒假，我没有选择回老家过年，而是留在家中专心写项目。记得那一年雪下得格外大，也是在那个冬天，我完成了人生中第一个开源项目——如今已收获500余个 stars。本打算今年重构，却始终抽不出时间。</p><p>​    大二上的寒假我没有选择回老家过年，而是选择留在家中写项目，还记得那一年的雪下的格外大，也是在那个冬天我完成了自己的第一个开源项目，目前已经达到500stars，本来想在今年重构来着，却一直找不出时间。</p><p>​    大二时，我机缘巧合地参加了新华三杯，并独自带队进入全国总决赛。第一次来到杭州，我不禁思考：未来的自己，是否也能进入像新华三这样的大厂？虽然最终未能获奖，但那次经历让我大开眼界。</p><p>​    国赛结束后不久，我开始投递简历，着手准备大二下学期的暑期实习。由于学校并不出众，从五月初到中旬，只有蔚来一家给了面试机会。那是我第一次面试大厂，发挥欠佳。</p><p>​    或许真的是命运使然在牛客上我看到那个招聘实习的帖子，正是后来我在携程实习时的 leader 发布的，他没有嫌弃我的学历，认真的看完我的简历后帮我约了面试。那个晚上躺在床上我辗转反侧，我不得不考虑这是否是我此生最后的机会。</p><p>​    幸运的是，这次命运眷顾了我，我成功拿到携程的实习offer。</p><p>​    初入上海，那是我第一次真正感受到一线城市的繁华。对于极少外出旅游的我而言，那份震撼至今难忘。</p><p>​    在携程的四个月里，我学到了许多，也更加坚定了留在互联网行业的信念。或许我们无法预知前路的结果，但持续的坚持，是唯一能做的事。</p><p>  ​九月份回到学校后，我开始筹备第二次实习。得益于携程的实习经历作为背书，到了十一月份，面试机会逐渐增多。可惜在第一次字节跳动的面试中，算法准备仍显不足，最终止步于二面。现在回想，那大概是我离字节最近的一次了吧。此后，我在三天内顺利通过了哔哩哔哩的面试，本以为短时间内不会再回到上海，没想到十二月又踏上了那片熟悉的土地。</p><p>  相比于携程的实习经历，第二段实习给我留下的最深印象并非工作内容，而是实习中遇到的人。没错，正是在那段时间，我遇见了那个让我至今难以忘怀的女孩。不知她如今的工作是否顺利，我们也已经很久没有再见面了呢。</p><p>​    三月份实习结束后我再次返回学校，这个时间我面临一个重大的抉择——继续准备暑期转正还是梭哈考研？这无疑是一个很艰难的抉择，而也在这个月我的奶奶离开了，一时间无力感充斥着我，一如当年爷爷走的时候我没有办法做任何事，但我知道我必须振作起来。</p><p>​    最终我选择了双向推进，在四月份我迎来大爆发，一连斩获五个大厂offer，最终选择去腾讯，对于一直想去深圳的我来说也算是圆梦吧。</p><p>​    也是在腾讯，我遇到了对于我职业生涯影响第二大的导师——miro哥，可以说他是我实习生涯中最好的导师。遗憾的是由于今年前端需求锐减，我没有转正留下来，不过miro哥也一直在关注我的秋招，给予过我很多帮助。</p><p>​    八九月份无疑是我最痛苦的一段时间，今年的前端由于太多985211涌入一时间强度激增，所幸的是这一次命运认可了我这一路走来的艰辛，在快手的大池子里我率先泡了出来，收到意向书的那一刻，也算是如释重负对这三年有了交代。</p><p>​    回首这一路，既有运气的成分，也有努力的痕迹。倘若当初没有抓住携程的机会，或许一切都不会发生。</p><p>​    三年风雪，我心顽如青山，不曾动摇。</p><style>p {
  text-indent: 2em;    /* 首行缩进两个字 */
  margin-bottom: 1em;  /* 段落间距 */
  line-height: 1.6;    /* 行高 */
}
</style></div><p style="text-align:right"><a href="https://linmoe.cn/notes/7#comments">看完了？说点什么呢</a></p></div>]]></description><link>https://linmoe.cn/notes/7</link><guid isPermaLink="true">https://linmoe.cn/notes/7</guid><dc:creator><![CDATA[林陌青川]]></dc:creator><pubDate>Sat, 08 Nov 2025 08:56:24 GMT</pubDate></item><item><title><![CDATA[秋招第一挂——米哈游]]></title><description><![CDATA[<link rel="preload" as="image" href="https://i.imgs.ovh/2025/07/24/Q8M8H.jpeg"/><div><blockquote>该渲染由 Shiro API 生成，可能存在排版问题，最佳体验请前往：<a href="https://linmoe.cn/posts/interview-experience/mhy">https://linmoe.cn/posts/interview-experience/mhy</a></blockquote><div><blockquote><p>📅 面试时间：2025 年 7 月 21日<br/>🏢 公司：米哈游<br/>💼 岗位：前端开发（提前批）</p></blockquote>
<hr/><h2 id="-">🧑‍💻 面试整体回顾</h2><p>​    近期许多公司陆续开启秋招，我在上周收到了米哈游前端提前批一面的邀请，还是挺激动的，毕竟提前批等于神仙打架。</p><p>​    趁着本周公司没啥大需求，我刷了一些 LeetCode 和八股文做准备。面试当天感觉整体还不错，强度略高于实习面，但在可控范围内。以下是我整理的面经记录（无录音，仅回忆）：</p><hr/><h2 id="-">📝 面试题汇总</h2><h3 id="--">一、自我介绍 &amp; 项目经历</h3><ol start="1"><li>自我介绍</li><li>介绍两个项目：
<ul><li>实习项目：D2C 提效方向（如 Figma to Code 自动化）</li><li>业务项目：负责业务模块或优化场景</li></ul></li></ol><hr/><h3 id="--">二、前端基础 &amp; 网络知识</h3><ol start="3"><li><p><strong>JavaScript 类型判断方式</strong></p><ul><li><code>typeof</code>：用于原始类型判断，<code>typeof null === &#x27;object&#x27;</code></li><li><code>instanceof</code>：检查原型链</li><li><code>Object.prototype.toString.call()</code>：最精确</li><li><code>constructor</code>：不稳定，可能被修改</li><li>对比它们的使用场景和优缺点</li></ul></li><li><p><strong>垂直居中常见写法</strong></p><ul><li>Flex 布局：<code>display: flex; align-items: center;</code></li><li>Grid 布局：<code>display: grid; place-items: center;</code></li><li><code>position: absolute + transform</code>：<code>top: 50%; transform: translateY(-50%)</code></li><li>单行文本：<code>line-height</code></li><li><code>table-cell</code>：早期兼容方案</li></ul></li><li><p><strong>从输入 URL 到页面渲染的完整流程</strong></p><ul><li>DNS 解析 → 建立 TCP 连接（三次握手）</li><li>发起 HTTP 请求 → 接收响应</li><li>解析 HTML → 构建 DOM &amp; CSSOM → JS 执行 → 页面渲染</li></ul></li><li><p><strong>Cookie / localStorage / sessionStorage 的区别</strong></p><table><thead><tr><th>特性</th><th>Cookie</th><th>localStorage</th><th>sessionStorage</th></tr></thead><tbody><tr><td>生命周期</td><td>可设置</td><td>永久</td><td>页面关闭失效</td></tr><tr><td>存储大小</td><td>~4KB</td><td>~5MB</td><td>~5MB</td></tr><tr><td>是否随请求发送</td><td>✅ 是</td><td>❌ 否</td><td>❌ 否</td></tr><tr><td>访问方便性</td><td>一般</td><td>✅ 简单</td><td>✅ 简单</td></tr></tbody></table></li><li><p><strong>浏览器缓存机制</strong></p><ul><li>强缓存：<code>Expires</code> 和 <code>Cache-Control</code></li><li>协商缓存：<code>Last-Modified + If-Modified-Since</code>、<code>ETag + If-None-Match</code></li><li>加载时判断缓存策略是否命中</li></ul></li><li><p><strong>DNS 解析过程</strong></p><ul><li>本地缓存 → 系统缓存 → 本地 hosts 文件</li><li>向 DNS 服务器发起递归查询（根 → 顶级域 → 权威域）</li></ul></li><li><p><strong>CDN 原理</strong></p><ul><li>内容分发网络，缓存静态资源到边缘节点</li><li>缓解源站压力，提升响应速度</li><li>具备回源机制，缓存失效自动更新</li></ul></li></ol><hr/><h2 id="-">✍️ 手撕算法题</h2><h3 id="-k-">第 K 个缺失的正整数</h3><h4 id="-">✅ 题目描述：</h4><p>给定一个递增排序的正整数数组 <code>arr</code>，表示某些正整数被缺失了，返回第 <code>k</code> 个缺失的正整数。</p><h2 id="">结语</h2><p>  慢慢来吧，还是对自己太自信了，没有认识到自己不足，学历在秋招确实是我的一大弱点，但客观如此也没法了...争取转正吧</p><p><img src="https://i.imgs.ovh/2025/07/24/Q8M8H.jpeg" height="970" width="1318"/></p><style>p {
  text-indent: 2em;    /* 首行缩进两个字 */
  margin-bottom: 1em;  /* 段落间距 */
  line-height: 1.6;    /* 行高 */
}
</style></div><p style="text-align:right"><a href="https://linmoe.cn/posts/interview-experience/mhy#comments">看完了？说点什么呢</a></p></div>]]></description><link>https://linmoe.cn/posts/interview-experience/mhy</link><guid isPermaLink="true">https://linmoe.cn/posts/interview-experience/mhy</guid><dc:creator><![CDATA[林陌青川]]></dc:creator><pubDate>Thu, 24 Jul 2025 03:34:46 GMT</pubDate></item><item><title><![CDATA[D2C：前端的自我革命]]></title><description><![CDATA[<p>当前内容无法在 RSS 阅读器中正确渲染，请前往：<a href="https://linmoe.cn/posts/fronted/d2c_2">https://linmoe.cn/posts/fronted/d2c_2</a></p>]]></description><link>https://linmoe.cn/posts/fronted/d2c_2</link><guid isPermaLink="true">https://linmoe.cn/posts/fronted/d2c_2</guid><dc:creator><![CDATA[林陌青川]]></dc:creator><pubDate>Sat, 31 May 2025 19:51:08 GMT</pubDate></item><item><title><![CDATA[D2C：人工智能时代下的一些思考]]></title><description><![CDATA[<link rel="preload" as="image" href="https://pic4.zhimg.com/v2-145cbc820cde357feb0b274d4462f667_1440w.jpg"/><link rel="preload" as="image" href="https://p.ipic.vip/i6aarm.png"/><link rel="preload" as="image" href="https://p.ipic.vip/nncja5.png"/><link rel="preload" as="image" href="https://p.ipic.vip/h104a4.png"/><div><blockquote>该渲染由 Shiro API 生成，可能存在排版问题，最佳体验请前往：<a href="https://linmoe.cn/posts/essay/d2c_ai">https://linmoe.cn/posts/essay/d2c_ai</a></blockquote><div><h2 id="">人工智能爆发</h2><p>​    其实对于大多数人来说人工智能在GPT出来之前是没有那么强的感知力的，也可以说是一个好的产品推动了整个市场的发展，还记得20年GPT3问世时候出圈般的热度，当然国内当时的热度可能比较小，也仅限于科技圈内的人使用比较多。</p><p>​    作为一个前沿科技爱好者，我对于新技术一直是保持接受态度的，毕竟这也是互联网这一行的特点，终生学习嘛，一直到后来到GPT4，Gemini，Claude等等国际大模型技术的涌现，似乎人工智能时代即将迎来大爆发，但国内似乎一直没有什么声响，包括腾讯，阿里，百度等一众互联网大厂在内，其实布局AI领域是很早的，特别是百度，从早在2010年时候就开始投入人工智能的研发，但似乎一直都没有好的产品，好吧，这也是我对于百度目前的刻板印象了，起个大早，赶个晚集。</p><p>​    一直到今年年初国产开源大模型DeepSeek的问世，国内的AI大模型才逐渐破圈被我们所熟知，搞笑的是随着DeepSeek的开源，许多大厂的大模型似乎都迎来了“突破”，字节的豆包和腾讯的元宝大多数时候还是接DeepSeek更好用哈哈哈。</p><p>​    就在本周Claude4.0正式被发布，因为最近在忙着做AI应用开发，许多大模型都测过一遍，Cladue无疑在代码生成上是最令我惊叹的，同时也不禁为程序员的未来产生了一丝担忧。当然AI的兴起唱衰程序员也不是一天两天了，不过作为一名程序员，有时候我们真的得好好思考一下我们相较于AI来说护城河在哪，未来又该何去何从。</p><p><img src="https://pic4.zhimg.com/v2-145cbc820cde357feb0b274d4462f667_1440w.jpg" alt="img" height="864" width="1440"/></p><h2 id="ai">AI工具提效</h2><p>​    如果你是一个合格的程序员，那么你一定是使用过cursor的，作为目前市面上最火爆的AI辅助编程工具，再加上Claude大模型的配合，可以说你只需要输入一句话他就能帮你实现你需要的产品，有个笑话是现在程序员的核心出装就是cursor充个pro版本再学一下git。</p><p>​    人是无法抗拒时代浪潮的，人工智能大势已定，全民AI时代未来将至，或许换个角度我们应该想办法与AI共存而不是必须死一个，毕竟以AI的知识库，写一个函数有时候考虑的比高级程序员还要多，这根本没有可比性。</p><h2 id="ai">AI的局限性</h2><p>​    当然从现在来看AI短时间内还是无法完全替代程序员的，我认为有三个点是以后需要突破的。</p><h3 id="1-">1. 生成内容的精确性</h3><p>​    有些时候你会发现AI的回答十分混乱，这个在人工智能领域有个专有名词叫“幻觉‘，对于一些复杂场景下生成的代码是无法直接拿来使用的，那么调整就十分的有必要了，调整又不可避免的需要读懂代码。</p><h3 id="2-">2. 上下文限制</h3><p>​    上下文限制一直是AI的一个长期问题，目前市面上最好的模型Claude4.0可以达到200k tokens，当然这一点随着AI的不断发展我觉得是会被不断解决的。</p><h3 id="3-">3. 沟通理解</h3><p>​    沟通理解我觉得才是AI无法替代程序员的重要因素，在一个需求从提出到上线交付的整个流程中，比如我是一名前端，我需要不断与产品交流，与UI设计对接，和后端联调，这其中的沟通成本是非常大的，以目前AI的能力还无法完全理解需求的含义，未来暂且不可知。</p><h2 id="d2c">D2C：毒瘤还是惊雷？</h2><p>​    D2C全称Design To Code，如其名，设计稿转代码，这也是目前各大厂一直在做的事情，设计稿的话比较常用的就是Figma了，如何将Figma转化成我们组内约定规范的React组件，这也是我最近正在研究的事情。也是基于对各大厂的方案调研后，我也有了自己的一套方法论。</p><p><img src="https://p.ipic.vip/i6aarm.png" height="521" width="1152"/></p><p>​    整体上是基于Dify去完成的串联，其实我们组内之前也有重构工程师在做类似的事情，整体是通过Figma插件导出HTML代码，再通过cursor进行组织成规范的React组件，整体上虽然效果不错，但是局限一方面是使用不便，对于组内很多人不太愿意去增加自身的使用成本，在和我mentor沟通中这也是我学到的一点，如果这个产品一开始就不好用，那这个产品注定只会是一个失败的产品。</p><p>​    这个月初我刚刚来公司，mentor就将这个重担丢给了我哈哈哈，组内的业务比较重，实习生刚刚来也没啥业务需求，刚好对这方面比较感兴趣就一直在研究，没想到也真做出了不少成果。</p><p><img src="https://p.ipic.vip/nncja5.png" height="1564" width="2782"/></p><p>​    目前能做到复现百分之90的设计稿，对于大多数业务场景都还能胜任，不过彻底投入生产可能还需要测试一段时间，对于第一阶段的最终形态，我们对标的是国外的Anima这个产品</p><p><img src="https://p.ipic.vip/h104a4.png" height="1162" width="2802"/></p><p>​    至于D2C是好是坏？我觉得仁者见仁了，这套方案可以让前端工程师更专注于业务逻辑而非UI，如果能真的成熟落地，至少在设计到前端复现UI上是极大提效的。</p><p>​    不过周五跟leader讨论了一下，他想看到的不仅仅是生成UI组件，还需要加上业务逻辑代码......其实第一阶段大部份公司都是可以实现的，但是为什么业务逻辑这方面市面上没有一个统一的方案，因为每个公司的业务逻辑复杂度是不同的，想让AI去理解你的业务逻辑，必须有一个庞大的知识库去进行约束，那么就不可避免的需要每个模块的复杂人去写一份文档了，讲道理这些项目动则七八年历史，屎山堆了一层又一层，你让他们自己讲都讲不清楚....所以很难搞啊。</p><p>​    不过也可以理解，生成UI还可以说提效，要是UI+逻辑全写出来还要我们前端工程师干啥😂。</p><h2 id="">结语</h2><p>​    AI目前来说更擅长的是做0到1的事情，0.5到1反而是很难的，比如一个七八年的项目你让AI去读，去新增，那是一件很难的事情了，所以目前还是不用那么焦虑的，积极的拥抱AI，这也是我们唯一能做的事情。</p>
<style>p {
  text-indent: 2em;    /* 首行缩进两个字 */
  margin-bottom: 1em;  /* 段落间距 */
  line-height: 1.6;    /* 行高 */
}
</style></div><p style="text-align:right"><a href="https://linmoe.cn/posts/essay/d2c_ai#comments">看完了？说点什么呢</a></p></div>]]></description><link>https://linmoe.cn/posts/essay/d2c_ai</link><guid isPermaLink="true">https://linmoe.cn/posts/essay/d2c_ai</guid><dc:creator><![CDATA[林陌青川]]></dc:creator><pubDate>Sat, 24 May 2025 17:17:16 GMT</pubDate></item><item><title><![CDATA[实习生涯的最后一站——腾讯TEG]]></title><description><![CDATA[<link rel="preload" as="image" href="https://p.ipic.vip/luidjv.jpg"/><link rel="preload" as="image" href="https://p.ipic.vip/2kta0z.jpeg"/><link rel="preload" as="image" href="https://p.ipic.vip/mtwf7d.jpg"/><link rel="preload" as="image" href="https://p.ipic.vip/68baxw.jpg"/><div><blockquote>该渲染由 Shiro API 生成，可能存在排版问题，最佳体验请前往：<a href="https://linmoe.cn/posts/essay/tx_teg">https://linmoe.cn/posts/essay/tx_teg</a></blockquote><div><h2 id="">前言</h2><p>​    如果你此刻正处在人生迷雾中，那希望这篇文章，能在某个瞬间，为你点亮一丝光。</p><p>​    在入职腾讯之前，我总共面试了腾讯九次、字节跳动六次。说实话，我也曾怀疑过自己是否真的行。但现实就是这样，我们永远无法预知幸运会在哪天降临，唯一能做的，是在它来临之前，做好自己能做的。</p><p>​    所以，我能告诉你三年前的我和此时的你一样郁闷吗？</p><p><img src="https://p.ipic.vip/luidjv.jpg" height="623" width="855"/></p><h2 id="">暑期实习乱斗</h2><p>​    今年的暑期实习启动得特别早，像腾讯的提前批在二月份就开始了。我算是“有幸”体验了一把被提前批面试官“拷打”的滋味——分别来自WXG和IEG，都是腾讯的核心业务线。其实在这之前，我也有两段还不错的实习经历，分别是携程的火车票团队和哔哩哔哩的大会员部门，算是都待在了“主战场”上。</p><p>​    坦白说，我的学历非常一般，选择前端除了兴趣之外，也有一点“避坑”思维——学历普通在后端这条路上确实更容易吃亏。</p><p>​    三月份我从哔哩哔哩离职后，一边回学校上课，一边着手准备暑期实习。老实讲，那时我对自己没什么信心，毕竟暑期实习流程更正式，难度也更接近秋招。当初其实一度准备放弃，甚至想“润”去考研。但心里总有点不甘心，于是决定多线程展开——整理项目经历，改简历，然后就开始投了。</p><p>起初机会不少，但很多面试死在了“手撕算法”环节，特别是字节的面试简直血雨腥风。血泪教训：算法写不出来，十有八九挂。</p><p>​    最开始基本都卡在一面，腾讯和字节我都勉强进了二面，但还是挂了。三月底那段时间对我的信心打击不小，一度怀疑之前那两段实习的offer是不是运气好而已。还好，我及时调整了状态，拼命刷leetcode，总结面试套路。终于，在四月底拿到了五家offer：</p><ul><li>腾讯 TEG</li><li>美团软硬件 SaaS</li><li>携程旅游</li><li>哈啰出行提效部门</li><li>腾讯云智电子签</li></ul><p>​    腾讯TEG是四月底拿下的，当时我都已经准备去美团了。没想到腾讯忽然来约面，我本着“刷个KPI”的心态去试了下。可能真的是时机到了，再加上四月中旬腾讯宣布扩招，这次流程推进非常快，四天内走完技术面，第二周周一HR面，审批一周后，offer终于落地。</p><p>​    看到短信的那一刻，我真的有点哽咽了。那个三年前看着别人手里offer发呆的少年，终于也走出了自己的路。</p><p><img src="https://p.ipic.vip/2kta0z.jpeg" height="977" width="1047"/></p><h2 id="">回顾来时路</h2><p>​    说到底，我是幸运的。从一所普通学校，一步步走到今天，少不了贵人的相助，也离不开自己的努力。对于很多人来说，从零到一是最难的，尤其是在没背景、没资源、没名校光环的情况下。</p><p>​    携程是我职业旅程的起点，也是至今最关键的一次转折。如果当初没能进入那个团队，或许也没有后来走进腾讯的我。直到今天我都感激那个愿意带我进组的Leader，对他来说可能是举手之劳，对我来说却是命运的分岔口。</p><p>​    还记得24年年初，那时候我没回家过年，为了能在大二暑假顺利找到实习，我留在家自学做项目。那年冬天特别冷，雪下得厚厚的，家里没人做饭，我干脆跑去我妈单位的保安亭“打工”蹭饭。说实话，做夜班保安也不算难熬，查岗少，我几乎每天在五平米的小亭子里写项目到凌晨两三点。也是在那儿，我完成了人生第一个开源项目：Memory Blog，如今它已经有了400个stars。</p><p><img src="https://p.ipic.vip/mtwf7d.jpg" height="1080" width="1440"/></p><h2 id="">近日心情</h2><p>​    这些天在公司还属于landing期，很开心遇到了一个很好的mentor，他叫Miro，我在公司的英文名是Kairo（其实我一开始准备沿用携程的Karen但是被注册了），还是很有缘份的哈哈哈哈，我似乎也是他第一个徒弟，对于我的提问他总是很耐心的给我解答，也会带我和其他同事交流，希望能留在这里。</p><p><img src="https://p.ipic.vip/68baxw.jpg" height="1280" width="1707"/></p><blockquote><p>人一生唯一需要征服的高山</p><p>是心中那个质疑自己的声音</p><p>有人总在等一句认可一次成功</p><p>才敢承认自己的价值</p><p>但真正的自信是无人鼓掌时依然向前的脚步声</p><p>世界是一面回音壁</p><p>你如何定义自己</p><p>他便如何回应你</p></blockquote>
<style>p {
  text-indent: 2em;    /* 首行缩进两个字 */
  margin-bottom: 1em;  /* 段落间距 */
  line-height: 1.6;    /* 行高 */
}
</style></div><p style="text-align:right"><a href="https://linmoe.cn/posts/essay/tx_teg#comments">看完了？说点什么呢</a></p></div>]]></description><link>https://linmoe.cn/posts/essay/tx_teg</link><guid isPermaLink="true">https://linmoe.cn/posts/essay/tx_teg</guid><dc:creator><![CDATA[林陌青川]]></dc:creator><pubDate>Sun, 18 May 2025 18:48:58 GMT</pubDate></item><item><title><![CDATA[近日有感～]]></title><description><![CDATA[<div><blockquote>该渲染由 Shiro API 生成，可能存在排版问题，最佳体验请前往：<a href="https://linmoe.cn/notes/4">https://linmoe.cn/notes/4</a></blockquote><div><h2 id="">前言</h2><p>​    不知道咋的最近有点摆，可能是刚刚拿到腾讯的offer让自己觉得安于现状？反省一下自己顺便写一写最近的一些思考感悟。</p><h2 id="">浅谈考研与就业</h2><p>​    作为一个考研就业两手抓的卷王，对于这方面还是有自信可以谈论一二的，目前的进度是五月份结束考研一轮（22408），暑期实习拿到包括腾讯美团在内的五家大厂offer，最近闲下来也开始思考自己的未来该如何选择。</p><p>​    首先是考研，作为大一刚刚进校就开始喊着要考研的选手，我也没有太辜负自己的期望，还是坚持了下来，就是没有考自己专业的研哈哈，可以理解进来的时候就对本专业不感兴趣。我是大三上正式开始备考的，可能和其他选手的备考路线不同我最开始备考的是专业课，大三上加上寒假完成408的一轮复习，三月份返校后用了两个月完成了基础课的一轮（不包括政治），其实主要复习也是在数学上，英语就是背背单词。</p><p>​    其次是就业，相较于考研来说就业我准备的时间就比较早了，大一到大二上一直都在打比赛，可惜自己在这方面确实是没什么天赋，拿到的成绩大多都一般，大二上的寒假果断花了两个月自己all in完成自己的第一个开源项目，并成功在大二下末尾拿到携程的offer，再到今年四月份暑期拿到腾讯的offer，可以说在我们学校也是少有来者了。</p><p>​    虽然是一直在两手抓，但最后肯定是要二选一放一个的，目前对于我来说性价比最高的肯定是报就业了，主要犹豫还是以下几点</p><ol start="1"><li>AI冲击下，前端的生存空间是否会被进一步挤压？</li><li>进入公司后续晋升是否会涉及到卡学历/学历高者优先提升？</li><li>考研上岸选择读研究生三年后的市场如何？</li><li>选择读研我能否在本科基础上延长职业寿命？提高薪资待遇？</li><li>读研能否前端转入算法岗？</li></ol><p>​    以上几点无疑最让我关心的就是当前前端形势问题以及后续晋升了，其实我参考了周围大部分研究生朋友的经历得出了几个结论，首先大部分研究生甚至包括92硕在内都走不了算法岗，最多就是AI应用开发，本质上还是走的开发，目前就业市场虽然算法岗位有所增加但整体上还是门槛很高，所以对于我来说读研大概率转不了算法，那么读研对于来说就只有提高学历这一个作用了，但是考虑到读研完后要花三年时间，这三年读研经历和工作经历，毫无疑问肯定是工作经验更有优势，所以目前我得出的结论是在能转正的情况下优先工作，考虑大龄读研刷应届生的身份进国企（可能会卡年龄限制🤔）。</p><h2 id="">浅谈薪资问题</h2><p>​    最近突然想到一个很怪的事情，那就是关于我的薪资问题，其实在互联网薪资问题属于一个红线话题，可以说高度保密的，也许是我还在实习对于这方面没有太过于重视，以至于大部分人问我薪资问题都如实回答了，这个得反省一下......虽然对于实习来说薪资在网上是透明的，但是不养成这种习惯，正式上班哪天嘴欠说出去就完蛋了。</p><h2 id="">浅谈最近备考以及某些焦虑</h2><p>​    不知道其他选手备考一天能学多长时间？我最近学习时间只能达到4-5h差不多，而且效率也没有太高，还是没有摆正自己的心态，也可能是没有all in的觉悟哈哈哈，今天看了一下APP的使用频率，在社交app上花的时间还是太长了，得找个办法限制一下，我也纳闷了平时也没啥人找我聊天咋花这么长时间的。</p><p>​    其二是最近看着学弟学妹们在空间发自己的代码截图突然有些羡慕或者说惆怅吧，似乎对于代码没有以前那种激情了，也可能是新鲜感过了...突然明白那句永远不要让你的兴趣成为工作，开源项目也堆积了很多技术债没有时间解决，等明年再找时间解决一下吧。</p><h2 id="">结语</h2><p>​    我发现我是一个很容易焦虑的人，总喜欢想点有的没的哈哈哈。</p><style>p {
  text-indent: 2em;    /* 首行缩进两个字 */
  margin-bottom: 1em;  /* 段落间距 */
  line-height: 1.6;    /* 行高 */
}
</style></div><p style="text-align:right"><a href="https://linmoe.cn/notes/4#comments">看完了？说点什么呢</a></p></div>]]></description><link>https://linmoe.cn/notes/4</link><guid isPermaLink="true">https://linmoe.cn/notes/4</guid><dc:creator><![CDATA[林陌青川]]></dc:creator><pubDate>Fri, 02 May 2025 17:15:24 GMT</pubDate></item><item><title><![CDATA[前端框架原理概览]]></title><description><![CDATA[<div><blockquote>该渲染由 Shiro API 生成，可能存在排版问题，最佳体验请前往：<a href="https://linmoe.cn/posts/fronted/frontend-framework-overview">https://linmoe.cn/posts/fronted/frontend-framework-overview</a></blockquote><div><h2 id="">前端框架原理</h2><p>现代前端框架几乎都是基于描述<strong><u>自变量</u></strong>和 <strong><u>UI</u><em></em></strong> <em></em>视图之间的关系建立的，即“数据驱动视图”</p><p>$         UI=f(state) $</p><p>前端经过长时间的发展，对于 <strong>UI </strong>的描述语言逐渐衍生出两种解决方案</p><ul><li>JSX（代表框架:React）:类 XML 语法的 ES 的语法糖</li><li>模版语法（代表框架:Vue，Svelte）</li></ul><h2 id="">前端框架分类的依据</h2><p>对于公式  <strong><font style="color:rgb(0, 0, 0)">UI = f(state) </font></strong><font style="color:rgb(0, 0, 0)">在“自变量与因变量”理论中，state 的本质是自变量，自变量通过直接或者间接（自变量导致因变量变化）的方式来改变 UI。“被改变的 UI”仅仅是”对宿主环境 UI 的描述“，并不是实际宿主环境的 UI。</font></p><font style="color:rgb(0, 0, 0)">所以，</font>**<font style="color:rgb(0, 0, 0)">UI = f(state) </font>**<font style="color:rgb(0, 0, 0)">可以进一步概括为两步：</font><ol start="1"><li><font style="color:rgb(0, 0, 0)">根据自变量（state）变化来计算出 UI 的变化</font></li><li><font style="color:rgb(0, 0, 0)">根据 UI 的变化执行具体宿主环境的 API</font></li></ol><font style="color:rgb(0, 0, 0)">至此我们可以根据</font>**<u><font style="color:rgb(0, 0, 0)">前端框架与自变量建立的对应关系的抽象层级</font></u>**<font style="color:rgb(0, 0, 0)">来划分前端框架</font><ul><li><font style="color:rgb(0, 0, 0)">元素级：Svelte</font></li><li><font style="color:rgb(0, 0, 0)">组件级：Vue</font></li><li><font style="color:rgb(0, 0, 0)">应用级：React</font></li></ul><h2 id="font-stylecolorrgb0-0-0font"><font style="color:rgb(0, 0, 0)">细粒度更新</font></h2><p>在 <strong>React</strong> 中定义因变量时候需要显式的指定出依赖项，而 <strong>Vue</strong> 和 <strong>Mobx </strong>不需要</p><pre class="language-jsx lang-jsx"><code class="language-jsx lang-jsx">// React
const y = useMemo(() =&gt; x * 2 + 1,[x]);
// Vue
const y = computed(() =&gt; x.value * 2 + 1);
// Mobx
const y = computed(() =&gt; x.data * 2 + 1);</code></pre><p>在 Vue 和 Mobx 中使用的“能自动追踪依赖的技术”被称为“细粒度更新”，它同时是许多前端框架剪力“自变量变化到 UI 变化”的底层原理。</p><h2 id="-react--hooks">实现 React 中的一些 Hooks</h2><blockquote><p>此处不管是 effect.deps 还是 state 对应的 subs 都使用了 Set 利用了集合不会重复添加数据的特性,用细粒度更新实现的 hooks 不需要去显式的指出依赖</p></blockquote>
<h3 id="41-usestate">4.1 useState</h3><pre class="language-jsx lang-jsx"><code class="language-jsx lang-jsx">function useState(value){
  // 订阅该state变化的effect
  const subs = new Set();

  const getter = () =&gt; {
    // 获取当前上下文的effect
    const effect = effectStack[effectStatck.length-1];
    if(effect){
      subscribe(effect,subs);
    }
    return value;
  }

  const setter = (nextValue) =&gt; {
    value = nextValue;

    // 通知所有订阅该state变化的effect执行
    for(const effect of [...subs]){
      effect.execute();
    }
  } 
  return [getter,setter];
}</code></pre><pre class="language-jsx lang-jsx"><code class="language-jsx lang-jsx">function subscribe(effect,subs){
  subs.add(effect);
  // 依赖关系建立
  effects.deps.add(subs);
}</code></pre><h3 id="42-useeffect">4.2 useEffect</h3><pre class="language-jsx lang-jsx"><code class="language-jsx lang-jsx">const [count,setCount] = useState(0);

useEffect(() =&gt; {
  console.log(&#x27;count is:&#x27;,count());
})
setCount(2);</code></pre><p>useEffect 实现的关键在于建立 useState 和 useEffect 之间的订阅关系</p><ol start="1"><li>在 useEffect 回调中执行 useState 的 getter 时，该 Effect 会订阅该 state 的变化</li><li>useState 的 setter 在执行时，会向所有订阅了该 state 变化的 effect 发布通知</li></ol><pre class="language-javascript lang-javascript"><code class="language-javascript lang-javascript">const effect = {
  // 用于执行useEffect回调函数
  execute，
  // 保存该useEffect依赖的state对应的subs的集合
  deps: new Set()
}</code></pre><pre class="language-javascript lang-javascript"><code class="language-javascript lang-javascript">function useEffect(callback){
  const execute = () =&gt; {
    // 重置依赖
    cleanup(effect);
    // 将当前effect推入栈顶
    effectStack.push(effect);

    try{
      // 执行回调
      callback();
    }finally{
      // effect出栈
      effectStatck.pop();
    }
  }

  const effect = {
    execute,
    deps: new Set();
  }

  execute(); // 自动收集依赖
}</code></pre><pre class="language-javascript lang-javascript"><code class="language-javascript lang-javascript">function cleanup(effect){
  // 从该effect订阅的所有state对应subs移除该effect
  for(const subs of effect.deps){
    subs.delete(effect);
  }
  effect.deps.clear();
}</code></pre><h3 id="43-usememo">4.3 useMemo</h3><pre class="language-jsx lang-jsx"><code class="language-jsx lang-jsx">function useMemo(callback){
  const [s,set] = useState();
  // 首次执行callback后，建立回调中state的订阅发布关系
  useEffect(() =&gt; set(callback()));
  return s;
}</code></pre><h2 id="aot--jit">AOT 与 JIT</h2><p> 所有现代前端框架都需要 “编译” 这一环节，而 “编译” 可以选择两个时机去执行：</p><ol start="1"><li><strong>AOT（Ahead Of Time，提前编译或预编译），宿主环境获取编译后的代码</strong></li><li><strong>JIT（Just In Time，即时编译），代码在宿主环境中编译并执行</strong></li></ol><p>在 Angular 中同时提供了这两种编译方案：</p><pre class="language-javascript lang-javascript"><code class="language-javascript lang-javascript">import {Component} from &quot;@angular/core&quot;;

@Component({
  selector: &quot;app-root&quot;,
  template: &quot;&lt;h3&gt;{{getTitle()}}&lt;/h3&gt;&quot;
})

export class AppComponent {
  public getTitle() {
    return &quot;Hello World&quot;;
  }
}</code></pre><p>渲染结果：</p><pre class="language-jsx lang-jsx"><code class="language-jsx lang-jsx">&lt;app-root&gt;
  &lt;h3&gt;Hello World&lt;/h3&gt;
&lt;/app-root&gt;</code></pre><p>如果将使用的 <strong>getTitle</strong> 方法换成一个未被定义的函数：</p><ol start="1"><li><strong>AOT</strong>：立即报错</li></ol><pre class="language-jsx lang-jsx"><code class="language-jsx lang-jsx">ERROR occurs in the template of component AppComponent.</code></pre><ol start="2"><li><strong>JIT</strong>：代码在编译时候不会报错，在浏览器运行的时候报错</li></ol><pre class="language-jsx lang-jsx"><code class="language-jsx lang-jsx">ERROR TypeError: _co.getTitleXXX is not a function</code></pre><p>除此之外还有这些区别：</p><ol start="1"><li><strong>JIT</strong> 的应用在首次加载的时候慢于 <strong>AOT</strong> 的应用，因为其需要先编译代码；而使用 AOT 的应用已经在构建的时候编译完成，可以直接执行代码</li><li>使用 <strong>JIT</strong> 的应用体积可能大于使用 <strong>AOT</strong> 的应用，因为其在运行时会增加编译器代码</li></ol><p>因此 <strong>Angular</strong> 一般在开发环境下使用 <strong>JIT</strong>，生产环境下使用 <strong>AOT</strong></p><h2 id="virtualdom-dom">VirtualDOM（虚拟 DOM）</h2><p>又称 <strong>VDOM </strong>是目前根据自变量变化计算出 UI 变化的一种主流技术</p>
<p>在 <strong>Vue</strong> 中使用<strong>模版语法</strong>来描述 UI，模版语法编译为 <strong><u>render </u></strong>函数：</p><ol start="1"><li><strong>render</strong>函数执行后返回“VNode 描述的 UI”，这一步骤中 Vue 中被称为 <strong>render</strong></li><li>将变化前后“VNode 描述的 UI”进行对比，计算出 UI 中变化的部分，这一部分在 Vue 中被称为 <strong>patch</strong></li></ol><p><strong>React</strong> 使用 <strong>JSX</strong> 来描述 UI，<strong>JSX</strong> 编译为 <strong><u>createElement</u></strong> 方法：</p><ol start="1"><li>createElement 方法执行后返回“React Elemet 描述的 UI”</li><li>“将 React Eleme 描述的 UI”与变化前“Fiber Node 描述的 UI”进行比较，计算出 UI 变化的部分，同时生成本次更新“Fiber Node 描述的 UI”</li></ol><h3 id="vdom-">VDOM 的优点</h3><ol start="1"><li>相较于 <strong>DOM</strong> 的体积优势：除了“比较 UI 变化需要必要的属性”，<strong>DOM</strong> 还包含了大量冗余的属性，使用 <strong>VDOM 可以减少内存的开销</strong></li><li>相较于 <strong>AOT</strong> 更强大的描述能力：比如要在“使用模版语法的前端框架”中实现 <strong>React</strong> 的 <strong>children</strong> 属性，需要实现 <strong>Slot Component</strong>，对 children 的简单操作也变成了对 <strong>Slot Component</strong> 的繁琐操作</li><li>多平台渲染能力：根据 $         UI=f(state) $中 f 的工作原理可以概括为
<ol start="1"><li>根据自变量变化计算出 <strong>UI</strong> 变化</li><li>根据 <strong>UI</strong> 变化执行具体的宿主 <strong>API</strong></li></ol></li></ol><p>因此在<strong>浏览器，Node </strong>宿主环境下使用 <strong>ReactDOM</strong> 包，在 <strong>Native</strong> 宿主环境下使用 <strong>ReactNative</strong> 包，在 <strong>Canvas</strong>，<strong>SVG</strong> 宿主环境下使用 <strong>ReactArt</strong> 包。</p><h2 id="react-">React 实现原理</h2><p><strong>React</strong> 被称为应用级框架的原因在于--其每次更新流程都是从应用的根结点开始，遍历整个应用。同理，<strong>Vue </strong>起始于组件，<strong>Svelte </strong>起始于元素。</p><hr/><style>p {
  text-indent: 2em;    /* 首行缩进两个字 */
  margin-bottom: 1em;  /* 段落间距 */
  line-height: 1.6;    /* 行高 */
}
</style></div><p style="text-align:right"><a href="https://linmoe.cn/posts/fronted/frontend-framework-overview#comments">看完了？说点什么呢</a></p></div>]]></description><link>https://linmoe.cn/posts/fronted/frontend-framework-overview</link><guid isPermaLink="true">https://linmoe.cn/posts/fronted/frontend-framework-overview</guid><dc:creator><![CDATA[林陌青川]]></dc:creator><pubDate>Sat, 26 Apr 2025 02:58:48 GMT</pubDate></item><item><title><![CDATA[上海折叠·终章]]></title><description><![CDATA[<div><blockquote>该渲染由 Shiro API 生成，可能存在排版问题，最佳体验请前往：<a href="https://linmoe.cn/notes/3">https://linmoe.cn/notes/3</a></blockquote><div><p>暮色漫上窗棂，收拾好工位告别 mentor。转身时字节跳动大楼的灯火正撞进眼底，千万格数据洪流在玻璃幕墙上蜿蜒流淌，将未说出口的告别冲散在霓虹里。</p><p>命运总是在制造精密的时间差，我想那些看似错轨的瞬间，实际是上帝在调试名为人生的沙盒——那段我们共同编译的短暂岁月，也许早已成为各自生命进程里不可替代的常量。相遇的意义在于照亮彼此，只要同行时是快乐的，便是最好的相遇。</p><p>如果有机会我想带你去看一看苏州河的黄昏，当波光将影子揉碎成十万片金箔，我们将听到这座城市用江水书写出的启示。</p><p>十二月的开卷铃声将比外滩跨年钟声更加洪亮，当试卷展开的刹那，洁白的卷面会倒映出我的过往，而所有未尽的遗憾，都将在下一个换乘站了却。</p><p>愿每个人的心中都有一座静安寺，在这喧嚣的城市中留存一份安宁。</p><p><strong>再见，上海。</strong></p><style>p {
  text-indent: 2em;    /* 首行缩进两个字 */
  margin-bottom: 1em;  /* 段落间距 */
  line-height: 1.6;    /* 行高 */
}
</style></div><p style="text-align:right"><a href="https://linmoe.cn/notes/3#comments">看完了？说点什么呢</a></p></div>]]></description><link>https://linmoe.cn/notes/3</link><guid isPermaLink="true">https://linmoe.cn/notes/3</guid><dc:creator><![CDATA[林陌青川]]></dc:creator><pubDate>Sat, 26 Apr 2025 02:44:06 GMT</pubDate></item><item><title><![CDATA[深入探究CSR与SSR并实现Mini React SSR]]></title><description><![CDATA[<div><blockquote>该渲染由 Shiro API 生成，可能存在排版问题，最佳体验请前往：<a href="https://linmoe.cn/posts/fronted/csr_ssr_react">https://linmoe.cn/posts/fronted/csr_ssr_react</a></blockquote><div><pre class="language-markdown lang-markdown"><code class="language-markdown lang-markdown">1. 使用了 `import` 语法，这是 `ES规范`，而非 Node.js 的 `CommonJS规范`。
2. 我们使用了 `React` 的 `JSX` 语法，`JavaScript` 并不认识，需要用 `Babel` 转译成这样。

修改 `package.json`:</code></pre>json
&quot;scripts&quot;: {
  &quot;start&quot;: &quot;webpack --config webpack.server.js &amp;&amp; node ./build/server.bundle.js&quot;
<p>}
```</p><p>此时运行 <code>node server.js</code> 可以成功渲染，但是只用 <code>renderToString</code> 将 <code>React组件</code> 转为了 <code>HTML字符串</code>，并没有任何的 <code>Hydrate</code>（水合）事件绑定，只有静态的 HTML。</p><hr/><h2 id="">绑定事件</h2><p>既然服务端只能渲染 HTML，客户端能渲染事件，那就结合一下，再实现一遍 <code>CSR</code>，让页面插入一个打包后的 <code>bundle</code>，挂载到相同的节点，让客户端将一模一样的内容重新渲染一遍，并绑定上事件（重复渲染后面解决）。</p><h3 id="clientjs"><code>client.js</code></h3><pre class="language-javascript lang-javascript"><code class="language-javascript lang-javascript">import React from &#x27;react&#x27;;
import { createRoot } from &#x27;react-dom/client&#x27;;
import App from &#x27;./pages/index&#x27;;

const root = createRoot(document.getElementById(&#x27;root&#x27;));

root.render(&lt;App /&gt;);</code></pre><h3 id="-serverjs">修改 <code>server.js</code></h3><pre class="language-javascript lang-javascript"><code class="language-javascript lang-javascript">import express from &#x27;express&#x27;;
import React from &#x27;react&#x27;;
import { renderToString } from &#x27;react-dom/server&#x27;;
import App from &#x27;./pages/index&#x27;;

const app = express();
app.use(express.static(&#x27;public&#x27;));
const content = renderToString(&lt;App /&gt;);

app.get(&#x27;/&#x27;, (req, res) =&gt; res.send(`
&lt;html&gt;
    &lt;head&gt;
        &lt;title&gt;Tiny React SSR&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;div id=&#x27;root&#x27;&gt;
            ${content}
        &lt;/div&gt;
        &lt;script src=&#x27;/client.bundle.js&#x27;&gt;&lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;    
`));

app.listen(3000, () =&gt; console.log(&#x27;listening on port 3000&#x27;));</code></pre><p>打包后的客户端代码被命名为 <code>client.bundle.js</code>，并放入 <code>public</code> 目录。</p><h3 id="webpackclientjs"><code>webpack.client.js</code></h3><pre class="language-javascript lang-javascript"><code class="language-javascript lang-javascript">const path = require(&#x27;path&#x27;);

module.exports = {
  mode: &#x27;development&#x27;,
  entry: &#x27;./client.js&#x27;,
  output: {
    filename: &#x27;client.bundle.js&#x27;,
    path: path.resolve(__dirname, &#x27;public&#x27;),
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: &#x27;babel-loader&#x27;,
          options: {
            presets: [&#x27;@babel/preset-env&#x27;, &#x27;@babel/preset-react&#x27;],
          },
        },
      },
    ],
  },
};</code></pre><h3 id="">现在的流程是</h3><p>先打包 <code>客户端</code> 的 <code>JS</code>，将引用 <code>pages/index.js</code> 核心 React 代码的 <code>client.js</code> 打包到 <code>public</code> 下的 <code>client.bundle.js</code>。</p><p>然后将同样引用 <code>pages/index.js</code> 核心 React 代码的 <code>server.js</code> 打包到 <code>build</code> 下的 <code>server.bundle.js</code> 中，然后 <code>node</code> 开启 <code>server.bundle.js</code>。</p><p>服务端会先渲染一遍组件代码，然后输出到 HTML 中，引用 <code>client.bundle.js</code>，然后用 JS 再渲染一遍，并绑定上事件。</p><h3 id="-packagejson">修改 <code>package.json</code></h3><pre class="language-json lang-json"><code class="language-json lang-json">&quot;scripts&quot;: {
  &quot;start&quot;: &quot;webpack --config webpack.client.js &amp;&amp; webpack --config webpack.server.js &amp;&amp; node ./build/server.bundle.js&quot;
}</code></pre><p>此时已经能交互，但是有个重复渲染问题需要解决。</p><h3 id="hydrateroot"><code>HydrateRoot</code></h3><p>React 官方提供了 <code>HydrateRoot</code> API，允许你在先前 <code>react-dom/server</code> 生成的 HTML <code>DOM节点</code> 中展示 <code>React组件</code>，简单来说就是<strong>复用服务器渲染出来的 DOM 节点</strong>。</p><h3 id="-clientjs">修改 <code>client.js</code></h3><pre class="language-javascript lang-javascript"><code class="language-javascript lang-javascript">import React from &#x27;react&#x27;;
import { hydrateRoot } from &#x27;react-dom/client&#x27;;
import App from &#x27;./pages/index&#x27;;

const root = hydrateRoot(document.getElementById(&#x27;root&#x27;));

root.render(&lt;App /&gt;);</code></pre><p>运行 <code>npm start</code>，实现了 SSR + Hydration 的 React 渲染。</p>
<style>p {
  text-indent: 2em;    /* 首行缩进两个字 */
  margin-bottom: 1em;  /* 段落间距 */
  line-height: 1.6;    /* 行高 */
}
</style></div><p style="text-align:right"><a href="https://linmoe.cn/posts/fronted/csr_ssr_react#comments">看完了？说点什么呢</a></p></div>]]></description><link>https://linmoe.cn/posts/fronted/csr_ssr_react</link><guid isPermaLink="true">https://linmoe.cn/posts/fronted/csr_ssr_react</guid><dc:creator><![CDATA[林陌青川]]></dc:creator><pubDate>Sat, 26 Apr 2025 02:39:37 GMT</pubDate></item></channel></rss>