<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>mylofi</title>
        <link>https://mylofi.fun/</link>
        <description>I'm Mylo, this is my blog, a tech &amp; life blog.</description>
        <lastBuildDate>Wed, 12 Aug 2026 08:22:57 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>zh-CN</language>
        <copyright>© 2026 Mylo</copyright>
        <item>
            <title><![CDATA[读完 DeepSeek 这篇推理加速论文，我满脑子只剩一句话：好钢用在刀刃上]]></title>
            <link>https://mylofi.fun/posts/dspark-no-peeking/</link>
            <guid isPermaLink="false">https://mylofi.fun/posts/dspark-no-peeking/</guid>
            <pubDate>Mon, 29 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[没被 DSpark 的调度打动，被它守的那条”不能偷看”的规矩打动了。工程里有些约束是护身符，不是镣铐。]]></description>
            <content:encoded><![CDATA[<p>前两天看到 DeepSeek 和北大合发了一篇《DSpark》。名字取得挺抽象，但做的事很实在——<strong>让大模型回答问题更快。</strong></p>
<p>33 页，读了我两个傍晚。合上 PDF 之后最大的感受，不是什么「又一篇顶会大作」，而是一个朴素到有点俗的理：</p>
<p>把算力用对地方，比堆更多算力值钱太多了。</p>
<hr>
<h3 id="大模型为什么一个字一个字往外蹦"><a href="#大模型为什么一个字一个字往外蹦">大模型为什么一个字一个字往外蹦？</a></h3>
<p>用 ChatGPT 或者 DeepSeek 的时候，我们都经历过那种感觉：光标一闪一闪，字一颗一颗往外弹。不是模型故意磨蹭，是它的工作机制就这样——自回归生成，每出一个字，必须把前面所有字重新读一遍。</p>
<p>100 字的回答，跑 100 趟完整计算。GPU 忙得脚不沾地，利用率还低得可怜。</p>
<p>业界折腾出一个办法，叫「推测解码」（Speculative Decoding）。思路很直：<strong>让一个小模型先把答案猜出来，大模型再一次性校对。</strong> 前面猜对了就留着，猜错了后面的就扔掉重来。</p>
<p>好比写作文先打草稿再誊——草稿越靠谱，誊得越快。</p>
<hr>
<h3 id="两派打架谁都没赢"><a href="#两派打架谁都没赢">两派打架，谁都没赢</a></h3>
<p>草稿怎么打？两派人吵了好几年。</p>
<p>一派老老实实，一字一字来。每个字都参照前一个，质量稳得很。代表是 Eagle3。可问题也在这儿：写 7 个字的草稿要跑 7 次计算。你草稿还没打完，誊写省的那点时间早赔出去了。</p>
<p>另一派就不客气了，一口气把所有位置同时填满，只跑一次计算。代表是 DFlash。快是真快，但准确率随位置暴跌。因为没有字与字之间的关联，写出来的东西经常精神分裂——比如「of course」和「no problem」，并行模型可能拼出「of problem」。每个字单独看都没毛病，连起来就是个灾难。</p>
<p><strong>快的不准，准的不快。</strong> 就尬在这儿。</p>
<hr>
<h3 id="dspark-的办法两边的便宜都占"><a href="#dspark-的办法两边的便宜都占">DSpark 的办法：两边的便宜都占</a></h3>
<p>DeepSeek 团队的想法很贼：既然并行快、自回归准，能不能各取所长？</p>
<p>他们搞了个「半自回归」架构，听着高深，拆开看就两层：</p>
<ul>
<li>主干继续并行跑，大块计算一步到位，速度不掉；</li>
<li>尾巴接一个极轻的串行模块，只干一件事：前一个字出来后，把下一个字的概率微调一下。比如已经写出了「of」，它就帮「course」加点分，给「problem」降降温。</li>
</ul>
<p>这个尾巴轻到什么程度？论文里的测试数据是，整个起草过程只比纯并行慢了 0.2% 到 1.3%。但 <strong>最终被大模型认可的字数涨了 16% 到 30%。</strong></p>
<p>几乎不花钱，效果明显变好。这种事谁都喜欢。</p>
<hr>
<h3 id="第二个暗坑验证"><a href="#第二个暗坑验证">第二个暗坑：验证</a></h3>
<p>草稿写得好是第一步。但如果每个字都老老实实送到大模型面前查一遍，照样不划算。尤其是在上万人同时用的场景下，验证算力是稀缺资源。</p>
<p>论文里有个特别反常识的结论：<strong>闭着眼睛把所有草稿字都验一遍，整体吞吐反而会掉。</strong></p>
<p>为什么？不是所有请求都一样。代码类的东西，结构固定，草稿准确率天生高。闲聊就完全是另一码事了，发散性强，靠后的字十有八九要被毙掉。一刀切地全验，等于在闲聊的时候拿宝贵的算力去赌几乎确定的失败。</p>
<p>所以 DSpark 又做了一件事：<strong>让模型自己评估每个草稿位置有多靠谱</strong>——论文里叫「自信头」（confidence head）。然后结合当前系统到底忙不忙，动态决定这次该验多长。</p>
<p>闲的时候，多验几个又不亏。忙的时候，只验最有把握的前缀，后面的直接砍。</p>
<p>这不就是餐厅的逻辑吗？没人的时候你翻菜单翻十分钟没事，满座的时候服务员恨不得你三秒点完。资源怎么分，得看压力。</p>
<hr>
<h3 id="上线后的数字比论文本身更有说服力"><a href="#上线后的数字比论文本身更有说服力">上线后的数字，比论文本身更有说服力</a></h3>
<p>最让我心里咯噔一下的，是生产环境的数据。</p>
<p>DSpark 已经跑在 DeepSeek-V4 的 Flash 和 Pro 两个线上版本了，替代了之前的 MTP-1。真实用户流量下：</p>
<ul>
<li><strong>V4-Flash：</strong> 每人每秒生成速度提了 60%–85%；</li>
<li><strong>V4-Pro：</strong> 提了 57%–78%。</li>
</ul>
<p>可更狠的不是这些百分比，是论文里那张吞吐—响应速度的图。</p>
<p>老办法 MTP-1，在高交互需求下（比如要求每秒给用户 120 个 token），并发量直接雪崩。几乎没法用。DSpark 把这个边界往外推了不止一档——以前那块地方是空的，现在可以站上去了。</p>
<p>不是优化，是解锁。</p>
<hr>
<h2 id="读完之后几点零散的想法"><a href="#读完之后几点零散的想法">读完之后几点零散的想法</a></h2>
<p>第一，DSpark 没造更大的模型，没堆更多的卡。做的事情说白了就是「半自回归 + 动态调度」两步棋，但每一步都掐在要害上。这让我想起很多年前有人说过：最好的工程不是没有约束，是在约束里找到最巧的解法。</p>
<p>第二，「浪费」和「节省」是同一个东西的两面。低负载时可以撒一点验证算力赌更高的速度；高负载下每一份都得精打细算。好的系统不是一刀切的「省」，是随压力自动变形。</p>
<p>第三，开源这事确实加分。DeepSeek 这次不光发了论文，还把 DSpark 的 checkpoints 和训练框架 DeepSpec 全放出来了。这意味着社区做推理加速研究的人不用重复造轮子，直接站肩膀上往下走。这种姿态比发论文本身更难得。</p>
<hr>
<h2 id="跟你有什么关系"><a href="#跟你有什么关系">跟你有什么关系？</a></h2>
<p>你大概率不会去读「推测解码」或「Pareto 前沿」，但这个事离你一点不远。</p>
<p>现在问 AI 一个问题，等几秒甚至十几秒才看到完整回答，是常态。DSpark 这类技术干的事就是在改这个常态：<strong>等待越来越短，体验越来越顺。</strong></p>
<p>而且推理成本一下来，很多以前「太贵搞不定」的场景就成立——实时语音代理、长期代码协作、多轮深度推演，这些都需要速度和成本同时达标。</p>
<p><strong>技术多数时候在你看不到的地方进步，但你能感觉到它。</strong></p>
<p>手机从 3G 换 4G 再换 5G，你没有去研究基站用了什么调制，但不卡了、画质清了——你能感觉得到，DSpark 也一样。</p>
<hr>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[把代码交给 AI 以后，我发现最不能交出去的是自己]]></title>
            <link>https://mylofi.fun/posts/the-last-checkpoint/</link>
            <guid isPermaLink="false">https://mylofi.fun/posts/the-last-checkpoint/</guid>
            <pubDate>Wed, 24 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[AI 正在接管越来越多的编码工作，但真正决定结果的，并不是“让 AI 做什么”，而是人是否还能定义意图、判断质量、承担结果。当代码不再需要亲手一行行写下，程序员真正需要守住的，可能是中间那一次判断和最后那一次验收。]]></description>
            <content:encoded><![CDATA[<p>最近在改一个项目，改法跟以前不太一样了。要做的事我不再一行一行自己敲，而是拆成一件一件丢给 AI，让它自己跑，我起来去接杯水，回来看，干完了，再丢一件，又去接水（主打一个少量多次）。突然就感觉有点恍惚，我已经记不清是从什么时候开始，不再亲手写代码了。</p>
<p>后来我把这件事拆开看，发现自己和 AI 之间，不知不觉夹进来一个我以前从没注意过的角色。</p>
<h3 id="多出来的那一层"><a href="#多出来的那一层">多出来的那一层</a></h3>
<p>以前我跟它相处更像打乒乓球，我发一个球它接一个，一来一回，节奏捏在我手里，球也在我手里。现在不像了，更像伺候一片菜地：要做的事我一件件点下去，就撒手不管了，地里头有个东西替我盯着，从地里挑一棵交给 AI 去弄，弄完了收回来看一眼，长好了就收，没长好就塞回去换个法子重来。我盯的是那片地，AI 盯的是手里那棵菜，而真正说了算的，是中间那个一直没合眼、AI 说长好了它也不肯信、非要亲自验一遍的东西。</p>
<p>这件事我盯着看久了，慢慢琢磨出点味道来。</p>
<p><img src="01-sleepless-checkpoint.png" alt=""></p>
<h3 id="它最会干的那种活"><a href="#它最会干的那种活">它最会干的那种活</a></h3>
<p>它最会干的那种活，有个共同的样子，就是答案其实已经摆在那儿了，只是要从一个地方搬到另一个地方。之前维护一个老项目，最早是拿一套语法写的，后来想整个换成另一套，换汤不换药，里头的逻辑原封不动，就外面那层皮得揭了重贴。搁以前这是个熬人但不熬脑子的体力活，现在我交给 AI，它干得又快又稳，因为原版就摆在旁边当尺子，它贴歪了我拿新旧两份一对比，立马看得出来。我又试着让它干另一种活，性能探索，想知道一段代码换个写法会不会更快，让它把能想到的方案都列出来挨个跑一遍，把数字排给我看，这种活它也不需要创造什么，只需要把所有的可能性穷举一遍，而它穷举起来不知疲倦。我渐渐发现它擅长的全是同一种活，就是那种不生产任何新意图的活，意图从头到尾都是我定的，它只负责照着我给的形状把东西挪到该在的位置，挪错了原来的形状还在那儿，对得上对不上眼一看便知。</p>
<p><img src="02-moving-without-new-intent.png" alt=""></p>
<p>反过来也就明白它怕什么了。</p>
<h3 id="它最怕的那种活"><a href="#它最怕的那种活">它最怕的那种活</a></h3>
<p>它最怕的是那种意图本身就说不清楚、做出来又得活很久的活儿，像业务代码、框架底层、几个团队约定好的一套契约，这类东西连我自己写之前都得在心里来回掂量半天到底要的是个什么，嘴上说的是加个登录，心里转着的是七八种边界情况和几种异常往后还要不要扩展跟隔壁系统怎么衔接。这种东西丢给 AI，它每次都能交回一份看着挺像那么回事的代码，问题在于它嘴里的“像那么回事”跟我心里那套模糊的标准之间，永远差着一道很窄的缝。单看一次无所谓，缝里塞点保险加点兜底，好像也没坏，可这套组合是会反复跑的，跑一次缝里多塞一点，跑十次塞了十层，塞到最后代码还是那个代码逻辑还是那个逻辑，我已经看不懂它了，它显出一副挺扛造的样子，但那扛造是一层一层兜出来的、堆出来的，不是设计出来的，我把“看着经得起用”和“真经得起用”这两件事彻底搞混了，更要命的是我根本不知道它哪天会从那条缝里漏出来。</p>
<p><img src="03-the-growing-seam.png" alt=""></p>
<p>上面这些其实都是技术问题，多盯两眼多复审几遍还能补回来，真正让我后背发凉的是另一件。</p>
<h3 id="后背发凉的那一件"><a href="#后背发凉的那一件">后背发凉的那一件</a></h3>
<p>我开始害怕自己慢慢变得离了这套东西就不会干活了。这话现在说出来显得矫情，可往回想想我们这一行每出一个新工具都顺手收走一点能力，用了版本管理没人记得清手动合并怎么搞，用了自动补全手敲完整 API 名字的人少了一半，现在轮到这套监工组合上场，它收走的可能是更大的一块，是独立判断一块代码好坏的那点本事。我已经在边缘上隐约感觉到这件事了，有时候想提个问题跟同事讨论一个设计，话到嘴边先愣一下，这事先让 AI 跑一遍再说吧，合并不合并不重要先让它过一遍。那个一直没合眼的东西，正在从我手边的工具，悄悄往我思考的前置条件上挪，挪过去很容易，挪回来就难了。</p>
<p>我知道有人听到这儿会想，那我干脆不用不就完了，这个念头我也起过，可站不住脚。</p>
<h3 id="躲不开"><a href="#躲不开">躲不开</a></h3>
<p>道理很简单，你不架这套，架这套的人会来碾你，最直接的碾法是速度，一个比你小一半的团队只要把这套用顺了，产出节奏是你追不上的，你还在一行一行敲，人家已经点下去撒手干别的去了，这不是愿意不愿意的事，同样的活人家成本比你低一截，时间长了市场自然投票。还有一种碾法更不讲理，是别人拿这套来对付你，有人想找你项目里的毛病，不用自己一行行读，让它连轴扫，扫到疑似就给你递东西过来，真的假的都来，你不接这套这套也会来找你，到最后还是得架一套去筛它递来的那些。所以要不要用，这问题早就被取消了，会用，真正的问题挪到了用了之后怎么不把自己也搭进去。</p>
<p>现在我把这些事捋在一起看，觉得它们有个统一的形状。</p>
<h3 id="瓶颈挪了地方"><a href="#瓶颈挪了地方">瓶颈挪了地方</a></h3>
<p>以前卡人的是做不出来，想法有了手跟不上，技术是瓶颈，现在那一头松了，AI 把“做”这一段吃得差不多了，可瓶颈没消失，它搬家了，搬到了两头。往前卡在到底要啥，意图说不清它就瞎猜，猜出来一份挺像样的我照单全收，那条缝就开始攒。往后卡在做出来的到底对不对，那份挺像样的代码是真经得起用还是看着经得起用，验它的力气一分没省。中间那段最顺的，恰恰是最不该松手的那段，就是判断它到底好不好值不值得留该不该这么长的那点判断本身，而这恰恰是这套组合唯一帮不了我的东西，偏偏它还最容易在这套组合里一天天地锈下去。</p>
<h3 id="该出手时别撂手"><a href="#该出手时别撂手">该出手时别撂手</a></h3>
<p>我不抗拒让它干，甚至乐意让它干，又快又稳，连着干几宿不带喘，这活儿它就是比我强，但有两件事我从头到尾没撒手。</p>
<p>一件是在它干活的过程中。它种菜之前，种什么、种哪儿、行距多大，这些事我不丢给它瞎猜，意图我说清楚，地我画好线，它只管照着点。它种到一半要是歪了，我当场就拦下来，不让它一路歪到底。这就跟前面那条缝对上了——意图我亲自定，它就没机会瞎猜，缝也就攒不起来。</p>
<p>另一件是它交回来的那一下。菜是它种的，长得也齐整，可烂没烂心、有没有生虫，这事它说了不算，我说了算。它交一筐，我并不是照单全收，还得自己验过、确认是真没坏才敢装进筐里。</p>
<p>这两件事，说穿了就是一句：中间不撒手，最后不放手。</p>
<p><img src="04-hands-on-the-middle-and-end.png" alt=""></p>
<p>道理也简单。菜端上桌，吃出问题来，没人会去问那台机器，问的是我。它干得再好，担责任的还是我，那么把关这一环，没法外包给它，也不该外包给它。</p>
<p>这会儿我又去接了杯水，回来看菜都收好了，齐齐整整摆在地上。我看了两眼，没急着装，挑了一棵最不起眼的，里里外外检查了一遍。检查完确认没长虫、没烂心，才装进筐里。</p>
<p>种菜可以交给它，收菜也可以交给它，唯独检查这一下，还得自己扎扎实实动手来。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[丰饶之后：腾讯这份报告，让我陷入了深思]]></title>
            <link>https://mylofi.fun/posts/after-the-abundance/</link>
            <guid isPermaLink="false">https://mylofi.fun/posts/after-the-abundance/</guid>
            <pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[代码白菜价了，瓶颈从"写"搬到规格、验证、品味，还有能不能兜得住。丰饶之后，稀缺没消失，它搬家了。]]></description>
            <content:encoded><![CDATA[<p>读了腾讯研究院那份《AI Coding 观察报告 2.0》，总共四十多页，花了快一个小时才看完，在这唠几句自己的想法。</p>
<p>不是要做书摘，是里面有几件事，看完之后一直在脑子里转，不吐不快，也正好用这篇文章理清一下思路。</p>
<hr>
<h2 id="先说最让我难顶的是什么"><a href="#先说最让我难顶的是什么">先说最让我难顶的是什么</a></h2>
<p>Anthropic 在 2026 年 4 月，9 天之内发了两个模型。</p>
<p>一个叫 Mythos Preview，代码测试跑到 93.9%。但不对外，只给 11 家“防御性安全伙伴”用。</p>
<p>9 天后，Opus 4.7 公开发布，87.6%。</p>
<p>差了 6 个点。这 6 个点哪儿来的？官方博文里有一句，原话大意是：Opus 4.7 是他们“第一个这类模型”，训练的时候，<strong>故意把某些能力削弱了</strong>，才放出来。</p>
<p>你品，你细品，看看这话说的。</p>
<p>意思是，他们手里有个更强的，强到你够不着。你能买到的那个，是被“降权”之后的版本。而且他们明着告诉你这事。</p>
<p>这跟以前“实验室藏着好东西”不一样。以前是藏着掖着，现在是<strong>公开发布机制本身就是分层的</strong>。他们甚至给这套玩法起了个名字，叫“双轨发布”。内部一条轨一直突破，外部一条轨挑挑拣拣、降了权、再喂给你。</p>
<p>报告管这叫“商业模型在台面趋同，储备能力在台面下分化”。六大商业模型的分数确实挤在 1 个百分点里，80% 出头，看着谁都能用。但那个 93.9% 的东西在那儿杵着，告诉你台面上的趋同是个假象。</p>
<p>我觉得这是整份报告里最值得留意的一件事，比模型分数本身重要得多。</p>
<p><img src="01-double-track-release.png" alt=""></p>
<hr>
<h2 id="然后是那个-22-倍"><a href="#然后是那个-22-倍">然后是那个 22 倍</a></h2>
<p>既然模型都差不多了，竞争靠啥？</p>
<p>报告说靠一个叫“驾驭工程”的东西。也就是最近很火的 Harness Engineering 这个概念，这个东西是在 2025 年底才被人正式起的名，2026 年初 OpenAI 发了篇同名博文，一下就火了。</p>
<p>啥意思呢？就是你别再纠结用哪个模型了，该花心思的是——怎么给 AI Agent 搭一套让它靠谱干活的系统。规格怎么写，约束怎么卡，记忆怎么管，出了错怎么兜回来。</p>
<p>有个数字，我得承认，看到的时候愣了一下。</p>
<p>SWE-bench Pro 这个测试上，<strong>换一套驾驭框架带来的分数波动，是换一个模型的 22 倍。</strong></p>
<p>22 倍。不是 22%。</p>
<p>你拿着同一个模型，给它套不同的“驾驭框架”，分差能拉到 6 到 10 个百分点。反过来，你死磕“该用 Opus 还是 Gemini”，那个差距可能不到 1 个点。</p>
<p>这事挺颠覆的。以前大家觉得模型是核武器，其他的不重要。现在模型都差不多，那个“其他的”反而成了真正的东西。</p>
<p><img src="02-harness-engineering-v2.png" alt=""></p>
<p>Anthropic 自己有个例子。他们早期 Sonnet 4.5 那会儿的框架，得把任务切成一个个短跑（sprint），跑一段重置一次上下文，因为模型上下文一长就“焦虑”，提前草草收尾。后来 Opus 4.5 能连续干 2 小时了，sprint 那套就拆了。</p>
<p>再到 Opus 4.7，合作伙伴说它会<strong>在写代码之前先做形式化证明</strong>。</p>
<p>先证明，再写。</p>
<p>这事我没法不觉得有点渗人。一个机器，开始自己验证自己了。</p>
<hr>
<h2 id="cli-这事我想了半天"><a href="#cli-这事我想了半天">CLI 这事，我想了半天</a></h2>
<p>报告里还有个判断，我反复读了几遍才反应过来。</p>
<p>说现在这些工具——Cursor 3 、Codex App 、Google Antigravity——它们的“主要使用者”，正从人变成 Agent 组。</p>
<p>不是「人也用 Agent 也用」。是主要使用者变了。人从敲代码的，变成调度好几个 Agent 的。</p>
<p>然后有个反直觉的：Agent 要跟外部世界打交道，靠什么？</p>
<p>命令行，CLI。</p>
<p>不是什么花哨的协议，是那个最老的、黑底白字的命令行。</p>
<p>有个对比我直接搬过来说：GitHub 的 MCP 服务器（一种 AI 工具调用协议），要往上下文里塞 <strong>5.5 万 tokens</strong>。用 <code>gh</code> 命令行，<strong>200 tokens</strong>。差 275 倍。可靠性，CLI 是 100%，MCP 是 72%。</p>
<p>为什么？报告解释得挺到位。AI 模型训练的时候，吃进去的真实代码里全是 shell 命令和脚本。它写一行 <code>gh pr list</code>，跟写一行 Python，对它来说一回事。但你要让它走 MCP 协议，得先读懂协议描述、解析工具列表、格式化调用、再解析返回。每一步都是多套一层皮。</p>
<p>说白了，对 Agent 来讲，命令行是母语，MCP 是外语。</p>
<p><img src="03-cli-native-language-v4.png" alt=""></p>
<p>所以行业好像在往一个分层上收敛。命令行管 Agent 自己干活这层（内循环），MCP 管跨系统协调那层（外循环），还有一个叫 Skills 的东西管标准流程，主要是给不会写代码的人用。</p>
<p>顺嘴一提，国内这边出了个怪现象。一周之内，网易云、钉钉、飞书、企业微信，集体开放了 CLI。海外是开发者推着走，咱们是平台自己往下推。超级 App 主动 CLI 化。搞不好能直接跳过 IDE 这一步，在聊天软件里就把 Agent 用了。</p>
<p>这块我其实没完全想明白后果。先记下。</p>
<hr>
<h2 id="写代码不是瓶颈了那什么是瓶颈"><a href="#写代码不是瓶颈了那什么是瓶颈">写代码不是瓶颈了，那什么是瓶颈？</a></h2>
<p>报告有个核心论点，对应它那个标题“丰饶之后”。</p>
<p>意思是这样：以前做软件，卡在“怎么实现”。现在 AI 把这一段吃得差不多了。但瓶颈没消失，它<strong>搬家了</strong>，搬到了两头。</p>
<p>往前，卡在“规格定义”——你到底要 AI 干啥，这个说不清，它就瞎写。</p>
<p>往后，卡在“验证维护”——AI 写出来的东西，对不对、安不安全、能不能维护。</p>
<p><img src="04-scarcity-moved-v2.png" alt=""></p>
<p>后面的数据不太好看。Veracode 发现 45% 的 AI 代码任务里掺了已知漏洞。GitClear 翻了 2.11 亿行代码，技术债务估摸涨了三到四成，重复代码翻 4 倍，重构掉了 60%。意思就是，代码生成白菜价了，但验证它、维护它的钱，一分没省。</p>
<p>前面有个实验挺有意思。KTH（瑞典那个皇家理工）让 AI 从一篇 926 字的英文规格，把自己整个重新生成出来。成功了。</p>
<p>这意味着啥？规格变成了那个“稳的东西”，代码反而退化成可再生的副产品。工程师的重心，从写代码挪到写规格了。已经有人这么干了，他们自己开玩笑说"用英语编程，提交的是 Go"。</p>
<p>还有一道墙，得提一下。有个叫“原型墙”的说法。</p>
<p>搞 vibe coding 的那帮人，老上演同一出戏。第一周，兴奋，AI 嗖地出个雏形，一个月 20 美元，看着像成了七成。第三周，慌，安全问题、各种边角情况往外冒。第二个月，放弃，维护成本飙到一个月 200，烂尾。</p>
<p>有个 Google 的工程师管这叫“70% 问题”：AI 写的代码看着 70% 对，可补完剩下 30%，比从头写还费劲。</p>
<p>那“新的稀缺”是什么？报告点得很直白。分发，运维，合规，还有品味，代码不稀罕了，品味稀罕了。</p>
<hr>
<h2 id="saas-那段我倒没那么悲观"><a href="#saas-那段我倒没那么悲观">SaaS 那段，我倒没那么悲观</a></h2>
<p>过去三个月市场上有个条件反射。Anthropic 一发东西，就有个软件公司股价挨刀。</p>
<p>2 月 5 号，Anthropic 发了 Cowork 和 Opus 4.6，FactSet 当天跌 10%。2 月 23 号，就发了篇关于 COBOL 现代化的博客，IBM 跌了 13.2%，是它 25 年最大的单日跌幅。就一篇博客。4 月 17 号 Claude Design 发布，Figma 跌了快 7 个点。</p>
<p>媒体管这叫“SaaS 末日”。</p>
<p>但报告有个更冷静的说法，我比较认同：SaaS 没死，是<strong>中间那一层</strong>在被吃掉。</p>
<p><img src="05-saas-middle-layer.png" alt=""></p>
<p>你看看挨刀的都是谁。设计工具、金融数据、老系统改造、单一工作流协同。共同点：把一个 API，包一层带收费界面的应用，就干这个。</p>
<p>与此同时两头在长。一头是大平台，Cursor 估值从 293 亿蹿到 500 亿，Anthropic 拿走企业 AI 开销的 37%。另一头是 Skills 这种，让不懂代码的人用 markdown 就能把自己的工作流固化成可复用的东西，直接绕开中间商。</p>
<p>有个预测是挺狠的：按座位收费这套，2028 年前得作废。以后按产出收。Salesforce 按对话次数收，Intercom 按解决了多少工单收。Anthropic 在试点按"省了多少工时"折算。</p>
<p>这个变化我觉得比单点股价那些事深。但 SaaS 要说全完蛋，我是不信的。复杂的工资、社保、跨国合规那摊事，再多的 vibe coding 也复制不了，被吃的只是那层“套壳”。</p>
<hr>
<h2 id="最后这条跟每个人都有关"><a href="#最后这条跟每个人都有关">最后这条，跟每个人都有关</a></h2>
<p>报告里最实在的一句，是 Anthropic 的 CEO 在达沃斯说的：以后工程师是编辑 Claude 的产出，不是自己写代码。</p>
<p>Replit 那个 CEO 有个分法，说是搞技术的往三个方向走：往下，系统编程、嵌入式、安全关键，越靠底层越难被替；留在中间，全栈、增删改查那些，最危险，因为这是 AI 最拿手的；往上，产品设计、用户体验、商业策略，越靠用户越得靠人。</p>
<p>数据已经出来了。软件开发岗位需求只剩 2020 年的 65%。初级岗从 30% 掉到 20%，高级岗快到 40%。跟驾驭工程相关的岗，LinkedIn 上涨了 250%。</p>
<p>但真正让我停下来想的，是另一个变化。非开发者，头一回以“构建者”身份进场了。</p>
<p>Epic Games 一半以上的 Claude Code 使用，来自非开发者。Bolt.new 六七成的用户不是传统程序员，是设计师、学生、健身教练、销售、老师。有个叫 Skills 的东西，让一个完全不会写代码的人，10 分钟用 markdown 写出第一个 Agent 能力。</p>
<p>“一人公司”从一种无奈，变成主动选的了。YC 那个创业营里，单枪匹马的创始人比例，一年从 23.7% 涨到 36.3%。Cursor 20 个人做到 1 亿美元年收入。Bolt.new 15 个人俩月做到 2000 万。</p>
<p>十个人干一百个人的活，这话一年前还像吹牛，现在成日常了。</p>
<p>但该泼的冷水还是要泼的，实际情况也不是那么乐观。报告里边自己也说了：非开发者撞上的那道“原型墙”，比专业的人还陡。没工程纪律的“一人公司”，维护成本能翻 4 倍。Skills 生态里 36% 的东西有安全缺陷。能力下放了，治理和审计的能力，反而更稀缺。</p>
<p><img src="06-developer-redefined.png" alt=""></p>
<hr>
<h2 id="读完之后"><a href="#读完之后">读完之后</a></h2>
<p>说实话，这份报告我前后读了两遍，中间隔了几天。</p>
<p>第一遍读完，觉得信息量很大，但有点散。第二遍再读，才发现它其实就在讲一件事——</p>
<p>丰饶之后，稀缺没消失，它搬家了。</p>
<p>从“写代码”，搬到了判断、验证、品味，还有把这一摊东西持续运转下去的工程纪律。</p>
<p>报告结尾那句英文，说得很妙：</p>
<blockquote>
<p><em>After the abundance, what remains scarce is judgment, verification, taste, and the discipline to keep it running.</em></p>
</blockquote>
<p>判断力，验证能力，品味，还有让它一直跑下去的纪律。</p>
<p>这话不带任何煽情，但它让我后背有点凉。因为这四样东西，恰恰是 AI 最帮不了你的那几样。</p>
<hr>
<h2 id="六个洞察概括成下面这张表"><a href="#六个洞察概括成下面这张表">六个洞察，概括成下面这张表</a></h2>
<p>原报告有六条，前面挑着讲了一些。剩下没展开的，搁这张表里：</p>
<table>
<thead>
<tr>
<th>报告原话</th>
<th>就是一句话</th>
</tr>
</thead>
<tbody>
<tr>
<td>模型加速趋同，前沿差距不减</td>
<td>六大模型分数挤在 1 个点里；可那个不公开的 93.9% 在拉开储备差距</td>
</tr>
<tr>
<td>Agent 原生成为工具演化方向</td>
<td>工具形态变 Agent 编排，接口收敛到命令行+协议+Skills 三层</td>
</tr>
<tr>
<td>代码生成规模化，验证成新瓶颈</td>
<td>45% 的 AI 代码带已知漏洞，技术债务涨三四成</td>
</tr>
<tr>
<td>构建零门槛，品味运营稀缺</td>
<td>能做出来不等于能跑起来，原型墙卡掉一大批</td>
</tr>
<tr>
<td>SaaS 正被重新分配</td>
<td>中间套壳层被吃，两头壮大</td>
</tr>
<tr>
<td>开发者被双向重定义</td>
<td>做的事变了（编排而非编写），能做的人也变了（非开发者进场）</td>
</tr>
</tbody>
</table>
<hr>
<p><em>本文是对腾讯研究院《AI Coding 观察报告 2.0 —— 丰饶之后》的读后感，所有数据来自原报告。</em></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[路边的]]></title>
            <link>https://mylofi.fun/posts/by-the-road/</link>
            <guid isPermaLink="false">https://mylofi.fun/posts/by-the-road/</guid>
            <pubDate>Thu, 29 Jan 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[夜色里，一个男人、一条河、一轮月亮，和一行路过的行人]]></description>
            <content:encoded><![CDATA[<p>一个男人
光着膀子抽着烟
坐在一张板凳上
也坐在一座桥上</p>
<p>背对着一条河
也背对着河里的月亮
面朝着一条河
也面朝着路上的车辆</p>
<p>一行人从他身后走过
他看不到一行人
也看不到身后的月亮</p>]]></content:encoded>
            <category>诗</category>
            <category>创作</category>
        </item>
        <item>
            <title><![CDATA[苏州：莫厘峰徒步]]></title>
            <link>https://mylofi.fun/posts/suzhou-moli-peak-hike/</link>
            <guid isPermaLink="false">https://mylofi.fun/posts/suzhou-moli-peak-hike/</guid>
            <pubDate>Fri, 09 Jan 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[周末短途苏州，莫厘峰徒步半途而废，误入日料街、观前街吃胡辣汤，香格里拉泳池与梅花糕]]></description>
            <content:encoded><![CDATA[<p>周五（2026.01.09），下班回到家，已经八点半，老婆已经把东西收拾得差不多了，我拿上充电器，换了件衣服就准备出门。</p>
<p>导航开始，路程两个小时。快到目的地时，老婆看了一圈外卖，惊叹于苏州怎么这么多王婆大虾，于是点了一份尝尝鲜。到达酒店之后，停好车拿着行李包便办理入住，之后在大厅里拿起外卖上了楼。说起来王婆大虾，闻着气味不觉得香，心想肯定不好吃，老婆也说和她想象中的味道不一样。这倒让我想起了老家的香格里拉和虾哺，专门做虾的，虾还都是去过虾线的，很香很好吃。做法是先把虾炸一遍，然后配上黄瓜条、玉米、薯条、豆芽在炒锅里加上调料炒一下，出锅前再撒上香菜和一把芝麻，香喷喷的一绝，还能搭上鱿鱼、排骨、鸡爪这些做个两掺。高中毕业后我还在虾哺做过三个月的兼职，这是一家清真店，不过有点扯远了，还是说回这次短途吧。</p>
<p>躺在床上一边休息一边找徒步路线。苏州真是一座对户外运动格外友好的城市--无论是两步路 app 还是小红书上，随便一搜都有很多推荐路线。本来计划去天池山，却又偶然发现莫厘峰的路线也很不错。翻了几篇攻略后，便决定改去莫厘峰了。</p>
<p>由于中午看《白色巨塔》，实在没忍住把最后一集追完了，导致整个下午都有些精神不佳。再加上回家路上 40 分钟的车程，接着又马不停蹄赶往苏州，身体与精神实在是已经疲惫不堪，于是放下手机很快就睡着了。</p>
<p>第二天睡到了十点多，起床之后收拾了一下便下楼退房，在附近吃了一碗牛肉面就出发前往莫厘峰。路程 40 分钟左右，我们把车停在了雨花胜境停车场，然后就顺着两步路上的轨迹导航开始走。</p>
<p><img src="01.jpeg" alt=""></p>
<p>徒步穿过了大概有三四公里的街区道路和居民区，这里的房子基本上都是瓦房，房顶上还有太阳能热水器，着实是古代建筑与现代科技结合的典范。路很窄，但很好走，而且很干净，每家门前都由一条又深又长的水沟贯穿着，像是这个村子的毛细血管一样。不过有的路段水很清澈，有的路段水很浑浊。</p>
<p><img src="02.jpeg" alt=""></p>
<p>村子里还碰到几只流浪猫，一点也不怕人，跟着我们一直喵喵叫。</p>
<p><img src="03.jpeg" alt="">
<img src="04.jpeg" alt=""></p>
<p>穿过村子之后，顺着路线继续往前，途中碰到一些和我们反方向的徒步者，迎面吹过来的风很大，还听到有人和同伴说看他们（指我们）还迎着风呢，我们心想到了下山的路段应该就是顺风了吧！一路上风景还不错，有很久没看到山山水水的景象了，实在令人心旷神怡，心情舒畅。此时已经走了大概五公里，时间已经是两点多了，我们刚刚爬上一个山坡，道路极窄，以至于两人只能一前一后向上走。这时一个不留神，只注意着爬坡了，忘记了看地图，老婆问我有没有走错，我就确认了一下路线，好像是走错了，这是才反应过来在刚路过的那个岔口应该往右拐。结果两人有些喘着开始下坡，另起一道。这次一边走一边看地图，走着走着发现当前位置已经偏离了轨迹（还发现轨迹上是有箭头指向的，我们是顺时针按照路线走的，正确的方向是逆时针），我们以为是 GPS 信号不好，就继续走了一段。果不其然，这时我们意识到刚刚那条路才是正确的。</p>
<p>这时候老婆有点泄了气，不想继续了，而且还担心走完后天黑，不太安全，这时候已经差不多三点，我寻思着再调头回去走另外一条道好了，在天黑之前肯定能下山，而且已走了大约三分一的路程，但是老婆已经没了心气儿，我也不好坚持，就这样原路返回了。我还时不时在“冷嘲热讽”唱着不着调的 freestyle，说第一次出来徒步才刚开始走上道儿就这么结束了，还说回去要买徒步装备等等一大堆的废话来调侃她。</p>
<p>不过玩笑归玩笑，但也得适可而止。</p>
<p>老婆信誓旦旦地保证：“晚上回去重新做个攻略，明天再战一回。”</p>
<p>我笑着，将信将疑：“好好好，这话可是你说的。”</p>
<p>老婆毅然答道：“当然是我说的，省得你老念叨我扫兴。”</p>
<p>我接过话打趣：“不会不会，那等会儿回酒店，你来开车？”</p>
<p>老婆干脆利落：“行！”</p>
<p>返回的路上，路过来时路的水沟，老婆说这水沟应该不是简单的水沟吧，如此绵长。我说这不就是山里的排水沟吗，难不成还会有什么名字。往前走着拐了个弯，看到前边有个行人，举着运动相机朝着墙上一块介绍碑一边拍一边念：响水涧原是一条从近300米高处的山坞中流出的山涧曲溪，犹如巨龙下海那样奔腾不息，惊天动地的轰鸣声，在向人们呼唤，又出状元了！东山人杰地灵，自古以来，出了两名状元，一名探花，50名进士。原来真有名字，叫响水涧。</p>
<p>老婆已经提前订了香格里拉，有泳池。回到酒店之后，休息片刻就出门觅食。酒店附近有条淮海商业街，我们步行过去，结果是误入歧途，这条街上全都是日式料理，于是我们打车去了观前街。到了观前街，已经很饿了，看见什么都特别有胃口，想吃，于是先买了一份正新鸡排，一边吃着一边走向方中山胡辣汤。</p>
<p>身为两个河南人，对胡辣汤简直是没有任何抵抗力（但是方中山不是我的菜，我更偏爱王忠圈）。到店点了一份两掺（胡辣汤+豆腐脑）、一碗豆浆、半张油饼、5 个煎包，味道还不错，吃完喝完心满意足地去逛观前街了。</p>
<p><img src="05.jpeg" alt="">
<img src="06.jpeg" alt=""></p>
<p>逛完观前街回了酒店，看时间还早，我们就准备去游泳，老婆很贴心地带了我俩的游泳装备，于是我们就去了 5 楼。到了泳池，三三两两几个人，和健身房、游泳馆里的泳池环境比起来好上不少，人少、清静。我刚下水，准备把手环（小米手环 8nfc 版）设置为游泳模式，结果手环一碰到水就开始震动，滑动屏幕没有反应，以为是进水了，摘掉之后放在了躺椅上。老婆不会游泳，害怕水，我们就找救生员借了浮板和手臂游泳圈，教了她一会儿之后，她就在旁边自己玩儿，我去游了几个来回。</p>
<p>从泳池回来之后，老婆说前脚掌有点疼，想着是今天走了不少路，而且路上还说这双鞋鞋底比较薄，脱了鞋之后看了看，有点起泡的迹象。</p>
<p>于是我说，“明天咱们就好好休息吧，不出门了。幸好今天提前回来了，不然脚上非得磨出两个大水泡不可。”</p>
<p>老婆半信半疑，打趣道：“哟，你不一直埋怨我扫兴呢吗？信你的鬼话才怪。”</p>
<p>我嘿嘿一笑：“此一时彼一时嘛。”</p>
<p><img src="07.jpeg" alt=""></p>
<p>香格里拉，不愧是五星级酒店，虽然这家是 2014 年开业，但装修还是很豪华，夜景也不错。第二天睡到八点半，去吃早饭，尝尝苏州本地的风味。整体来说味道还不错，尤其是这个梅花糕，深得老婆喜爱，还问了服务员能不能打包，服务员说按理是不能打包，但是如果实在爱吃，可以用餐巾纸包一两个装在口袋里带出去，咳，谁让餐厅师傅手艺这么好呢，我们也是没法抵挡美食的优化，就带了两个回房间。</p>
<p><img src="08.jpeg" alt="">
<img src="09.png" alt=""></p>
<p>回到房间后，就开始补觉，昨天晚上睡得晚，又要起这么早，实在是又困又没精神。这一睡就到了下午两三点，房间是四点退房，我们起床后收拾完毕就启程回沪。一个不慌不忙、半“徒”而废的周末就此结束，苏州，我们下次再来。</p>]]></content:encoded>
            <category>随笔</category>
            <category>旅行</category>
        </item>
        <item>
            <title><![CDATA[冷冻街：人生像今夜]]></title>
            <link>https://mylofi.fun/posts/lengdongjie-tonight-like-this/</link>
            <guid isPermaLink="false">https://mylofi.fun/posts/lengdongjie-tonight-like-this/</guid>
            <pubDate>Fri, 26 Dec 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[育音堂里二三十人的演出，主唱红了眼眶；散场后老友打来视频，问在外漂泊的人苦不苦]]></description>
            <content:encoded><![CDATA[<blockquote>
<h4 id="20251226"><a href="#20251226">2025.12.26</a></h4>
<p>育音堂 C 厅</p>
</blockquote>
<p>到了现场发现只有寥寥十几人，有点出乎意料，可能是今天提前二十分钟入场的缘故吧。令人惊喜的是今天有一个暖场乐队 Line in ，看了他们的主页，目前只发行了四首歌，但是都很好听，像是把一杯雪碧倒在加冰块的杯子里，然后慢慢冒出气泡的感觉，湿冷湿冷像往年上海的冬天。今年上海的冬天十分干燥，鼻孔断断续续的出血有一个多月都没有完全恢复。</p>
<p>Line in 演出结束后，他们开始清理设备，我问 bass 什么时候发行新专辑，她说明年。我又问明年一定会发吗？她说包的，我说好好好，开始期待起来。</p>
<p>接下来冷冻街上台，这次得知他们有演出还是在演出前一天打开秀动看了一眼，偶然刷到了演出信息，要不然又会再次错过。 2022 年 4 月份，他们官宣了 10.22 号在上海的演出，那时候买完票就开始了等待，意想不到的是在 10.18 这天等来了演出取消的信息，因为那时候疫情还没有完全结束。</p>
<p>设备整理完毕后，演出开始，吉他贝斯鼓躁响起来的时候，我也开始摇头晃脑，熟悉的感觉回来了，我喜欢在 livehouse 的里随音乐律动的手舞足蹈。第一首《电子零》演出结束后，主唱高川子说他们对育音堂有着很深的情节，上次来到上海育音堂还是七年前，我看到他顺着脸颊流下来的眼泪，和红色的眼眶，川子老师的真情流露，很难不让人动容。育音堂对于上海每一个喜欢音乐和现场的人来说都是无可替代的象牙塔，已然是这些人心中不可磨灭的符号和象征，尤其是 2025 年，育音堂的搬迁和重建，这一路走来，大家相聚又分离再到重逢，实属不易。</p>
<p>前排零零星星几个人，演出时陆陆续续进场了一些，但是总数不过二三十人的样子，我时不时往后瞅一眼，心里有些许失落。演出间歇时，有一个乐迷和川子老师说她看了看以前的购票记录，他们上次来上海是五年前而不是七年，票价是 80 块钱，2025 年他们的预售票依然是 80 块钱，如今来到演出现场的人却三三两两。</p>
<p>不过现场的氛围依然热情高涨，我还被拉入了开火车的行列，大家都很开心也很享受，我突然觉得这也是一种少数人的浪漫吧，人生像今夜，时而熙熙攘攘，时而清清静静。</p>
<p>演出结束后，我大声喊向川子老师说我想要演出歌单，他从地板上撕下胶带，然后把歌单递给了我。然后我去买了一张《唯美一代》，等了一会儿他们过来签售，写了 to 签：一切顺利，然后在歌单后边写下了当天的演出时期和地点，以做纪念。</p>
<p>从地下的场地出来后，抬头望去这四周的高楼大厦都一模一样，一时分不清方向。我一脸迟疑地往右手边走，去找我从地下车库上来的电梯入口。绕了一圈也没找到，恰巧看到两个穿着同款大衣、看似物业工作人员的路人，于是我朝他们走去，端着手机给他们看我来时拍的入口照片，他们给我指了指，最后找到了入口。</p>
<p>停车费付了 35 块钱，真不便宜。导航里的这段内环高架真不好开，限速 60 而且只有两个车道，进趟城里也不容易，城里不见得是多好的地方。车里放着《唯美一代》，让我一直在回味今天的演出。当时一直在猜想乐队成员们的心里活动，不知他们看着场下的稀疏人群是什么感受，会不会很失落？但是随着演出的进行，慢慢意识到我实在是太多虑了，无论是台下还是台上，热烈的气氛完全让我沉浸其中。签售时我向他们展示付款后的界面，乐队成员对我说随便拿随便拿，他们表现地很谦逊又非常平易近人，我问有没有乐迷群，说是有一个但是比较冷清，平时没什么人说话，我说没关系没关系，只要能第一时间追踪到你们的演出信息就行。</p>
<p>大约开了一半的路程，手机打来视频电话。是老赵打来的，他和老秃正在喝酒。我说你们今天喝得是真高兴，他俩看到我正在开车就叮嘱我开车一定注意安全，说先不聊了随即挂了电话。</p>
<p>今天是我哥在老家办庆生宴的日子，也就是我小侄子的满月宴。一群朋友伙计聚在一起喝酒聊天，白天喝完一场觉得不尽兴，晚上又约了一场，老赵和老秃这俩货特别能喝，这些都是我在老家的发小，差不多从 2008 年开始玩到了现在的好哥们，每次回去我们都会找个地儿坐坐聚聚，但是喝酒我可不如他们，上次过年回去还把我给喝吐了，也是难得高兴。</p>
<p>到了小区把车停好后，我坐在车里给他们打了视频过去。他俩已经在路上了，一人拎着一瓶啤酒，看样子是还没喝多。</p>
<p>“今天是真高兴啊，喝得尽兴了吧”，我说。</p>
<p>“那必须的，高兴得很，这不晚上又来了一场。”</p>
<p>“你俩真牛，真能喝，没人喝得过你俩。”</p>
<p>从俩人言谈举止就能看出来喝得很尽兴。</p>
<p>“在那边咋样啊？过得好不好，苦不苦？”一副酒气模样的问我。</p>
<p>“好着呢，苦啥苦，刚搬完新家。”</p>
<p>“那以后去上海就有落脚的地儿了呀！”</p>
<p>“那是当然，吃够管够，随时来随时招待！”</p>
<p>电话两头都笑得合不拢嘴。</p>
<p>他们知道我一人在外，离家很远，除了工作上来往，没有什么交心的朋友，平时找个排忧解闷的哥们喝酒也找不来一两个，所以才问我过得好不好，再加上今年结了婚、买了房、装修，很多事情要忙，对于哥俩的关怀，我内心十分感动，一年也就见个一两次面。聊着聊着又说了一些兄弟情谊之间肉麻的话，虽然肉麻，但心里却明白是怎么个事。</p>
<p>不知不觉聊了半个小时，约好下次回家再聚，我也进了电梯上了楼。</p>
<blockquote>
<p>这时的我得到了顽固的弱点是未知的漫长</p>
<p>用一生的精力去寻找和发现这完整的力量</p>
<p>他有足够足够的理由去相信</p>
<p>危险想法确实从来没有过</p>
<p>如果黑暗中的每一个人</p>
<p>清澈的眼神</p>
<p>-- 人生像今夜</p>
</blockquote>
<p><img src="01.jpeg" alt=""></p>
<p><img src="02.jpeg" alt=""></p>
<p><img src="03.jpeg" alt=""></p>]]></content:encoded>
            <category>随笔</category>
            <category>音乐</category>
        </item>
        <item>
            <title><![CDATA[讷于言而敏于行]]></title>
            <link>https://mylofi.fun/posts/slow-in-speech-quick-in-action/</link>
            <guid isPermaLink="false">https://mylofi.fun/posts/slow-in-speech-quick-in-action/</guid>
            <pubDate>Thu, 29 May 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[从一句旧签名说起：慎言真言、脚踏实地，与小庙里大师的一席话]]></description>
            <content:encoded><![CDATA[<blockquote>
<p>2025.05.29</p>
</blockquote>
<p>几年前以这句话作为自己的掘金签名，最近又在思考到底该如何才能做到讷于言而敏于行。讷于言告诉我们要慎言、少言、真言，敏于行告诉我们要行动敏捷、脚踏实地、实践出真知。反思自己，我还远远没有达到这个境界，都说小鬼难缠，小人难防，人与人的区别都在哪里呢，我反复思考，结果在于一个“行”字，无论什么样的处世学问都能从一个人的“行”上看出这个人到底是什么类别。当你真诚待人的时候，别人不一定会真诚待你，在利益面前，只要能够获取更多的利益，那么这样的价值观和行事准则对他人来说就是对的，哪有什么标准。</p>
<p>一则趣事。假期之间在家悠闲自在，偶然在一个小庙里碰见一位大师，坐下来伸出手掌还没来得及说一句话，只是问了下姓名，便开始滔滔不绝说起来。其中有一点，说让我不要和小人纠结，避免口舌之争，斗不过小人，因为我为人正直善良，对待朋友真诚付出，但收到的回报却远不及所付出的，劝我退一步开阔天空，大师所言确实令我信服。我也就更想说服自己，不要再内耗，徒增自己的心智负担，做好自己的事情，但是真的很难去面对那些不公平，还要忍气吞声去面对那些人和事，希望自己更加努力做到莫向外求，但从心觅吧。在此也时刻提醒一下自己，不要同流合污与小人沆瀣一气，在利益面前，坚持自己的原则，柳暗花明又一村，事情迟早都会迎来转机的。</p>
<p>顺便记录一下大师说的其他，大意是这样：不要刻意求财，脚踏实地可以实现自己的价值，财自然回来。不要轻易被别人的诋毁和恶言所伤，修炼自己的内心，自强不息。</p>]]></content:encoded>
            <category>随笔</category>
        </item>
        <item>
            <title><![CDATA[花开了，我们去看看吧]]></title>
            <link>https://mylofi.fun/posts/flowers-bloomed-lets-go-see/</link>
            <guid isPermaLink="false">https://mylofi.fun/posts/flowers-bloomed-lets-go-see/</guid>
            <pubDate>Fri, 21 Mar 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[加班归家的清晨，受伤的膝盖和重新跑起来的双腿，还有拍完婚纱照、领了结婚证的喜悦]]></description>
            <content:encoded><![CDATA[<blockquote>
<p>2025.03.21</p>
</blockquote>
<p>忙碌的日子一直没停下来，昨天又加班到十一点多，打车到家已经十二点，身心疲惫。回到家里，迎来了老婆的拥抱，浑身的困倦立即烟消云散，但还是被嫌弃说好臭的一身班味，说完又轻轻亲了我一下，嘻嘻。😄</p>
<p>随后简单洗漱了一下，把大黄抱进了被窝准备睡觉，放下手机前看了一眼天气预报，阳光明媚的一天即将到来。☀️</p>
<p>九点钟起床，拉开窗帘果然是阳光灿烂的一天，已经感受到身体充满了能量，于是开始洗漱，刷牙的同时做了 50 个深蹲，吃了两片华夫饼🧇，开始做热身运动。</p>
<p>距离上次晨跑差不多已经一个月了，这期间去了两家医院看膝盖伤。</p>
<p>一个周六的上午，去了华山医院，运动医学科的名声在全国都是数一数二的，进了门诊室后，医生捏了一下膝盖，询问了基本情况，诊断为髂胫束的问题，开了几盒膏药和口服药，还有一周一次的冲击波治疗，早已听闻冲击波巨疼，这时候我已经感受到了未知的恐惧。医保支付了八百多，结束之后我寻思着应该没有这么严重吧，我也知道是跑步不科学，短时间跑量骤增的原因才导致的髂胫束紧张，也查过相关的资料，根本原因应该是臀中肌力量不足的原因，总之还是听医生的吧。哦对了，医生说让我放弃跑步这项运动，这个建议我还是不听了，跑了几个月，刚刚开始热爱上这项运动，怎能轻言放弃。🏃‍♂️</p>
<p>这个周六的第二天，又去曙光医院挂了个骨科，医生让拍了片子，结果出来之后说是滑膜炎，我给医生看了下华山医院医生开的膏药和口服药，医生说这些都是止痛的西药，没什么效果，于是又给我开了几盒膏药和口服药，看成分应该全都是中药，我心想着如果这两个医生要是碰面了，是不是还得干上一架。</p>
<p>上次跑步是在 02.26，养了一个月的时间，高高兴兴拎着垃圾下楼。开始跑起来，还是往常的路线，熟悉的感觉井然有序地回到了腿上、双脚、胸腔和嘴巴上，看着前方的路，眼睛稍微被太阳晒得有些睁不开，出门前没想着要戴防风眼镜，但是却没想起来它本身是个遮阳镜。手环上熟悉的每公里震动也让我不断兴奋，到了第三次震动，我觉得膝盖有点不舒服，但是还不太确定，于是我开始掉头往回跑，遇到红绿灯停下来摸了下膝盖外侧，好像没什么疼痛感。过了红绿灯继续往回家的路上行进，到了五公里的时候，疼痛感已经开始明显，所以我再也不敢逞强了，放慢速度直到停下，开始走着回家。</p>
<p>到家之后吃了一根香蕉，开始做拉伸动作。结束之后换衣服放进洗衣机开始洗澡，手机播着时过夏末的新专辑《未完》。</p>
<p>准备吃饭，贴心的老婆在昨晚已经做好了今天的午餐，本来是要带去公司吃，由于加班比较晚，今天就在家吃完饭再去公司。</p>
<p>最近经历了很多事情，每一件事情都值得拿出来好好絮叨一番。</p>
<p>工作上，不顺心的事情太多，想要写出来的时候却不知道从何说起，只觉得职场很难，想要用心把事情做好，最后却被卷入了尔虞我诈的浑水之中，没有得到好的结果，我也没有和人明争暗斗的本事，还同时也让我进一步提高了自己的忍耐上限，无奈地感叹一句就这样吧，没什么办法。我也怀念当年自己那股嫉恶如仇的勇气，只可惜如今身在其中有很多因素不得不考虑，只能委曲求全，曾经的滚动的石头也不断在被慢慢磨去棱角，但还是以声音碎片的一句“只有滚动的石头才能不长青苔”为慰藉吧。</p>
<p>生活上，当然还是很幸福开心，工作只是其中一小部分，不如意的事情十有八九，但总有快乐的东西给我们生活的增添色彩。</p>
<p>比如我们顺顺利利地拍完了婚纱照，从清晨的兴奋、开心到疲惫、笑僵的晚上，再到最后的满怀期待，一切都是让我继续前行的动力。</p>
<p>再比如我们开开心心地领了结婚证，从此以后我们就是余生彼此的伴侣，也同样让我对以后的生活充满期待，一切的美好，都会如期而至。</p>
<p>今天就写到这儿，摘一句歌词作为结尾，来自《未完》里的终曲。</p>
<blockquote>
<p>“我们并肩微笑，看巨浪遮蔽蕉阳。无人在意的，花已然开放。”</p>
</blockquote>]]></content:encoded>
            <category>随笔</category>
        </item>
        <item>
            <title><![CDATA[十公里]]></title>
            <link>https://mylofi.fun/posts/take-up-running/</link>
            <guid isPermaLink="false">https://mylofi.fun/posts/take-up-running/</guid>
            <pubDate>Thu, 28 Nov 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[🏃第一次挑战长距离，开启美好新一天]]></description>
            <content:encoded><![CDATA[<p>2024年 11 月 24 号，并不像往常的周日一样躺在床上睡懒觉，这是一个令人期待的早晨。昨天晚上定了今天早上八点的闹钟，准时起床，洗脸刷牙，随后吃了一片披萨🍕，换上过时的老款跑鞋，准备下楼做热身运动。</p>
<p>对，今天准备挑战一下自己跑个十公里，这将是我第一个十公里慢跑，心里还是有一点点的兴奋和激动。从十月份开始想要培养一个运动的爱好，一方面可以强身健体，另一方面还能把自己从繁忙的工作中抽离出来。所以选择了开始慢慢跑步，上个月只跑了三次，但还是对跑步这项运动有了兴趣，没什么成本，也不需要刻意学习和训练，唯一的成本也就是时间了。由于通勤时间比较长，工作日加班次数也不固定，所以决定早起晨跑，不过早起确实比较困难，但是当我第一天早起时还挺兴奋的，六点半的闹钟开始震动，脑子里是又困又清醒。</p>
<p>于是我就开启了跑步的旅程。</p>
<p>这周二和周四分别跑了 6.01 公里和 4.91 公里，心率一直很高，平均心率冲到了 170 ，让我有点不知所措，上周跑的几次平均心率都在 150 左右，后来咨询了一下沨哥的建议，让我不要太在意心率，也有可能是天气影响的，冬天降温时跑步心率也会增高，放慢速度让心率慢慢降下来就好了，不要刻意追求速度，跑前热身更久一些，还分享了很专业的拉伸动作，感谢沨哥。带着这些疑惑调整了心态，开始了今天的十公里。</p>
<p>热身完毕，蓄势待发，跑起来之后看着心率还是在 170 左右，但是体感舒适，所以也就没放在心上。</p>
<p>继续跑，今天的耳机里播着法兹的新专辑《东方101 与未来马场》，这张旧曲新编的合辑，已经霸占了我最近播放量的前列，非常有诚意的一张新作品，把以前的老歌重新制作，赋予了新的能量和生命力，编曲也更加浑厚和丰富，贝斯简直是太拨动我的心弦了。回想四年前在杭州第一次看法兹的现场，被深深震撼，已经迫不及待想要看下个月在摩登天空的演出了。关于新专辑的详情介绍：<strong>过往十五年间，我们只是微不足道的烟尘，迷失、搏击、幻想成为一体。握着彼此手，化身一粒石子奋力坠入水中，涟漪如生命般荡开。告诉自己，继续走，再慢一点。虽未到达草原，但我们的歌谣从不单调贫瘠。</strong></p>
<p><img src="after-fazi.jpg" alt="" title="2020.08.20 法兹演出后的现场"></p>
<p>跑了差不多七公里的时候，配速还是七分多钟，心率也一直没降下来，我就抬起胳膊保持静止，盯着手环上的数据四五秒钟，我惊人地发现心率在直线下降至 135 左右，令我非常诧异，心想是不是手环有 bug 啊！然后我就突然兴奋起来，不管三七二十一加速往前冲，跑到了 616 的配速，兴奋劲儿还没降下来就一直跑，跑着跑着膝盖有点不舒服也直接忽略不计了，继续跑完剩下的两公里就完成了今天的目标，跑着跑着感觉膝盖又没有不舒服了，觉得自己能就这么一直跑下去，左右脚轮流向前一直循环。最后两圈跑到了 552 的配速，终于，第一个十公里解锁成功。心里有了莫大的满足和开心，跑完之后开始做拉伸活动，回到家里冲完澡，吃了鸡蛋、牛奶、披萨补充能量，开启了精神抖擞的一天。</p>
<p>希望自己能够坚持一直跑下去，为自己加油。</p>
<blockquote>
<p>我很想知道，跑步的真谛究竟是什么。</p>
<p>我也是，灰二哥，我也想知道，虽然我一直在跑，但现在我还是不知道这个问题的答案。直到现在，我跑步时都仍会思考这个问题，今后也会不停问自己。
我真的很想知道。</p>
<p>所以，让我们一起跑吧，跑到天涯海角。</p>
<p>信念发出的光芒，永远存在我们心里。在黑暗中照亮延伸向前的道路，清楚地为我们指引方向。</p>
<p>———《强风吹拂》</p>
</blockquote>
<p>以前我总是会有迷茫和不知所措的时候，也想要一直寻找一个答案，但是随着岁月流逝，后知后觉的我才意识到，所有的问题好像并没有什么标准答案，只要我们不停下脚步，一直向前走，迟早都会发现，答案也许就在风中飘扬着。</p>
<p><img src="bpm-speed.jpg" alt="" title="心率/配速"></p>]]></content:encoded>
            <category>运动</category>
            <category>随想</category>
        </item>
        <item>
            <title><![CDATA[使用 Nginx 部署一个静态页面]]></title>
            <link>https://mylofi.fun/posts/nginx-conf/</link>
            <guid isPermaLink="false">https://mylofi.fun/posts/nginx-conf/</guid>
            <pubDate>Tue, 28 Mar 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[在服务器上使用 Nginx 部署一个 Hello World]]></description>
            <content:encoded><![CDATA[<h3 id="上传静态资源"><a href="#上传静态资源">上传静态资源</a></h3>
<p>首先把本地的一个 <code>index.html</code> 文件上传至服务器，然后发布进行访问。</p>
<p>首先进入到 <code>root</code> 目录下新建 <code>www</code> 文件夹</p>
<pre><code>cd /root &#x26;&#x26; mkdir www
</code></pre>
<p>然后在本地执行以下命令，将 <code>index.html</code> 文件上传至 <code>/root/www</code> 目录下：</p>
<pre><code>// 上传本地文件
scp index.html root@123.249.15.191:/root/www
</code></pre>
<p>其他文件传输操作：</p>
<ul>
<li>上传本地目录到服务器：<code>scp -r dist root@123.249.15.191:/root/www</code></li>
<li>从服务器下载文件：<code>scp root@123.249.15.191:/root/www/index.html</code></li>
<li>从服务器下载目录：<code>scp -r root@123.249.15.191:/root/www  /var/www</code></li>
</ul>
<h3 id="安装-nginx"><a href="#安装-nginx">安装 nginx</a></h3>
<p>执行命令以检查 <code>yum</code> 源中是否存在 nginx 包：</p>
<pre><code>yum list nginx
</code></pre>
<p><img src="list.png" alt="" title="已安装的示例图">
使用 <code>yum</code> 安装 nginx：</p>
<pre><code>yum install -y nginx
</code></pre>
<p>出现 <strong>Complete!</strong> 提示即安装成功：
<img src="install.png" alt="" title="已安装的示例图">
此时我们可以通过浏览器访问服务器地址，会看到 nginx 默认页面，如下：
<img src="hello-nginx.png" alt="" title="nginx 默认页面"></p>
<h3 id="配置-nginx"><a href="#配置-nginx">配置 nginx</a></h3>
<p>执行以下命令进入 nginx 目录，并修改配置：</p>
<pre><code>cd /etc/nginx
vim nginx.conf
</code></pre>
<p>在 <code>server</code> 中配置静态服务 <code>location</code> ，同时 nginx 还可以对网站的静态资源在传输前进行压缩，提高页面加载速度。经过 gzip 压缩后页面大小可以变为原来的 30% 甚至更小。使用时仅需开启 gzip 压缩功能即可。完整配置如下：</p>
<figure data-rehype-pretty-code-figure=""><pre tabindex="0" data-language="toml" data-theme="solarized-light gruvbox-dark-medium"><code data-language="toml" data-theme="solarized-light gruvbox-dark-medium" style="display: grid;"><span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">  user nginx;</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">  worker_processes auto;</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">  error_log /var/log/nginx/error.log;</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">  pid /run/nginx.pid;</span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#93A1A1;--shiki-light-font-style:italic;--shiki-dark:#928374;--shiki-dark-font-style:italic">  # Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">  include /usr/share/nginx/modules/*.conf;</span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">  events {</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">      worker_connections 1024;</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">  }</span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">  http {</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">      log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">                        '$status $body_bytes_sent "$http_referer" '</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">                        '"$http_user_agent" "$http_x_forwarded_for"';</span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">      access_log  /var/log/nginx/access.log  main;</span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">      sendfile            on;</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">      tcp_nopush          on;</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">      tcp_nodelay         on;</span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#93A1A1;--shiki-light-font-style:italic;--shiki-dark:#928374;--shiki-dark-font-style:italic">      # 开启gzip压缩功能</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">      gzip   		on;</span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#93A1A1;--shiki-light-font-style:italic;--shiki-dark:#928374;--shiki-dark-font-style:italic">      # 设置允许压缩的页面最小字节数; 这里表示如果文件小于10k，压缩没有意义.</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">      gzip_min_length 10k;</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2"> </span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#93A1A1;--shiki-light-font-style:italic;--shiki-dark:#928374;--shiki-dark-font-style:italic">      # 设置压缩比率，最小为 1，处理速度快，传输速度慢；</span></span>
<span data-line=""><span style="--shiki-light:#93A1A1;--shiki-light-font-style:italic;--shiki-dark:#928374;--shiki-dark-font-style:italic">      # 最大压缩比可设置为 9，但是处理速度较慢，推荐设置为 6</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">      gzip_comp_level 6;</span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#93A1A1;--shiki-light-font-style:italic;--shiki-dark:#928374;--shiki-dark-font-style:italic">      # 设置需要压缩的文件, 通常情况下文本、css、js建议压缩</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">      gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2"> </span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">      keepalive_timeout   65;</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">      types_hash_max_size 2048;</span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">      include             /etc/nginx/mime.types;</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">      default_type        application/octet-stream;</span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#93A1A1;--shiki-light-font-style:italic;--shiki-dark:#928374;--shiki-dark-font-style:italic">      # Load modular configuration files from the /etc/nginx/conf.d directory.</span></span>
<span data-line=""><span style="--shiki-light:#93A1A1;--shiki-light-font-style:italic;--shiki-dark:#928374;--shiki-dark-font-style:italic">      # See http://nginx.org/en/docs/ngx_core_module.html#include</span></span>
<span data-line=""><span style="--shiki-light:#93A1A1;--shiki-light-font-style:italic;--shiki-dark:#928374;--shiki-dark-font-style:italic">      # for more information.</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">      include /etc/nginx/conf.d/*.conf;</span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">      server {</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">          listen       80 default_server;</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">          listen       [::]:80 default_server;</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">          server_name  _;</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">          root         /usr/share/nginx/html;</span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#93A1A1;--shiki-light-font-style:italic;--shiki-dark:#928374;--shiki-dark-font-style:italic">          # Load configuration files for the default server block.</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">          include /etc/nginx/default.d/*.conf;</span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">          location / {</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">            root /root/www;</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">            index index.html index.htm;</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">            try_files $uri $uri/ /index.html;</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">          }</span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">          error_page 404 /404.html;</span></span>
<span data-line=""><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">              location</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984"> =</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2"> /</span><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">40x.html {</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">          }</span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">          error_page 500 502 503 504 /50x.html;</span></span>
<span data-line=""><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">              location</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984"> =</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2"> /</span><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">50x.html {</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">          }</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">      }</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">  }</span></span></code></pre></figure>
<p>配置完成之后，执行 <code>nginx -s reload</code> 重启 nginx 后通过浏览器访问，发现报 500 内部服务器错误：
<img src="500.png" alt="" title="500 Internal Server Error"></p>
<h3 id="排查问题"><a href="#排查问题">排查问题</a></h3>
<p>通过上文中配置可以看到，第 3 行中的错误日志路径为：<code>error_log /var/log/nginx/error.log;</code>
此时我们通过命令查看 <code>cat /var/log/nginx/error.log</code> 错误日志，由 <code>Permission denied</code> 可以看出是权限问题导致。
<img src="permission.png" alt="" title="权限错误"></p>
<p>1.首先，我们通过 <code>ps aux | grep nginx</code> 命令查看当前 nginx 的运行进程：
<img src="process.png" alt="" title="当前进程"></p>
<p>2.其次，我们修改上文配置中的第一行：</p>
<figure data-rehype-pretty-code-figure=""><pre tabindex="0" data-language="toml" data-theme="solarized-light gruvbox-dark-medium"><code data-language="toml" data-theme="solarized-light gruvbox-dark-medium" style="display: grid;"><span data-line=""><span style="--shiki-light:#93A1A1;--shiki-light-font-style:italic;--shiki-dark:#928374;--shiki-dark-font-style:italic"># 将用户名 nginx 改为 root</span></span>
<span data-line=""><span style="--shiki-light:#DC322F;--shiki-dark:#CC241D">user root;</span></span></code></pre></figure>
<p>3.最后，执行 <code>nginx -s reload</code> 重启 nginx ，再次打开页面看到已经可以正常访问：
<img src="hello-world.png" alt="" title="hello-world"></p>
<h3 id="常用命令"><a href="#常用命令">常用命令</a></h3>
<ul>
<li><code>nginx</code> 启动服务</li>
<li><code>nginx -s reload</code> 重启，每次修改配置文件后都需要重新启动才能生效</li>
<li><code>nginx -s stop 或 nginx -s quit</code> 关闭服务</li>
</ul>
<p>以上📝</p>]]></content:encoded>
            <category>nginx</category>
        </item>
        <item>
            <title><![CDATA[记 Git 目录体积过大的优化方案]]></title>
            <link>https://mylofi.fun/posts/git-slim/</link>
            <guid isPermaLink="false">https://mylofi.fun/posts/git-slim/</guid>
            <pubDate>Tue, 20 Dec 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[一次优化 Git 历史提交中包含对大文件引用的过程]]></description>
            <content:encoded><![CDATA[<p>Git 版本仓库提交过多，会导致项目根目录下的 <code>.git</code> 文件夹体积巨大，原因可能不只是单纯的提交历史过多，而是历史提交中包含有对大文件的引用，即使现在的项目中已经不存在这些文件了，但其引用关联依旧会被 <code>git</code> 保留下来。</p>
<h2 id="踩坑方案一"><a href="#踩坑方案一">踩坑方案一</a></h2>
<p><code>git filter-branch</code> 命令可以改写历史中大量的提交，但是它有很多陷阱，而且官方文档中已经不推荐使用它来重写历史了，当然，这个坑是我踩过之后才知道的。</p>
<h3 id="识别查询大文件"><a href="#识别查询大文件">识别查询大文件</a></h3>
<p>找到项目根目录下的 <code>.idx</code> 文件，路径：</p>
<blockquote>
<p><code>.git/objects/pack/pack-************.idx</code></p>
</blockquote>
<p>执行：</p>
<blockquote>
<p><code>git rev-list --objects --all | grep -f &#x3C;(git verify-pack -v  .git/objects/pack/******.idx| sort -k 3 -n | cut -f 1 -d " " | tail -10)</code></p>
</blockquote>
<p>运行结果大致如下：</p>
<figure data-rehype-pretty-code-figure=""><pre tabindex="0" data-language="text" data-theme="solarized-light gruvbox-dark-medium"><code data-language="text" data-theme="solarized-light gruvbox-dark-medium" style="display: grid;"><span data-line=""><span>c0b33abdf3af4f0a4ae82d6243954eeb344432d9 src/components/Emoji/emoji.png</span></span>
<span data-line=""><span>a08b3b0f766d26729cbaf0b7e86212b0ca4a5569 dist/js/2a10361c.async.js</span></span>
<span data-line=""><span>1d26f0da81c885c676badb026367a47183013fb5 dist/js/84ad94bf.async.js</span></span>
<span data-line=""><span>eb07071cdea7e019953a3a6778a4bb6e728ea13d dist/js/4922a65f.async.js</span></span>
<span data-line=""><span>7ddf057a0e26f300137c84cf03dbe088a69da488 dist/js/62f9d99c.async.js</span></span></code></pre></figure>
<h3 id="删除文件"><a href="#删除文件">删除文件</a></h3>
<p>将该文件从历史记录的所有 tree 中移除，执行：</p>
<blockquote>
<p><code>git filter-branch --index-filter 'git rm --cached --ignore-unmatch  src/components/Emoji/emoji.png'</code></p>
</blockquote>
<p>注：需要依次执行该命令去删除这些大文件，可能会有很多 <code>jpg/js.map/gif</code> 等类型的文件。</p>
<h3 id="推送到远程"><a href="#推送到远程">推送到远程</a></h3>
<figure data-rehype-pretty-code-figure=""><pre tabindex="0" data-language="text" data-theme="solarized-light gruvbox-dark-medium"><code data-language="text" data-theme="solarized-light gruvbox-dark-medium" style="display: grid;"><span data-line=""><span>rm -rf .git/refs/original/</span></span>
<span data-line=""><span>git reflog expire --expire=now --all</span></span>
<span data-line=""><span>git fsck --full --unreachable </span></span>
<span data-line=""><span>git repack -A -d</span></span>
<span data-line=""><span>git gc --aggressive --prune=now</span></span>
<span data-line=""><span>git push --force</span></span></code></pre></figure>
<p>依次执行完以上命令后，此时去检查远程仓库，结果令人诧异，居然...没有...生效...本地确实是清理掉了一部分空间，从 <code>1.2G</code> 瘦身到 <code>600M</code> 左右，但是推送后并没有作用，于是继续寻找其他方案，结果看到 <a href="https://stackoverflow.com/questions/2100907/how-to-remove-delete-a-large-file-from-commit-history-in-the-git-repository?answertab=modifieddesc&#x26;newreg=adaec4ffc87445179ca5946bf95f0109#tab-top">stackoverflow</a> 上有一个一摸一样的问题，按 <code>Date modified (newest first)</code> 排序之后，看到👇
<img src="1.png" alt="" title=" ">
也就是说 2022 了，<code>git filter-branch</code> 已经不好使了，推送到远程之后没有任何作用，方案一以失败告状。</p>
<h2 id="终极方案二"><a href="#终极方案二">终极方案二</a></h2>
<p><code>git</code> 官方文档推荐了这个库： <a href="https://github.com/newren/git-filter-repo">git-filter-pro</a> ，它是一个可以重写 git 历史的多功能 <code>Python</code> 脚本，即使现在在项目当中找不到那些历史文件，它依然可以找到它们并进行清理（看来这才是我想要的东西）。</p>
<h3 id="安装-git-filter-pro"><a href="#安装-git-filter-pro">安装 git-filter-pro</a></h3>
<blockquote>
<p><code>brew install git-filter-repo</code></p>
</blockquote>
<p>❌ 报错</p>
<blockquote>
<p><code>No such file or directory @ rb_sysopen -xxxxx</code></p>
</blockquote>
<p>✅ 解决方案</p>
<blockquote>
<p>原因是使用国内镜像但是该镜像未完全同步的问题，临时去除镜像即可：
<code>export HOMEBREW_BOTTLE_DOMAIN=''</code></p>
</blockquote>
<h3 id="如何使用"><a href="#如何使用">如何使用</a></h3>
<p>这里可以搭配此命令来找到那些历史中的大文件，然后逐一清理。</p>
<blockquote>
<p><code>git rev-list --objects --all | grep -f &#x3C;(git verify-pack -v  .git/objects/pack/******.idx| sort -k 3 -n | cut -f 1 -d " " | tail -10)</code></p>
</blockquote>
<p>假设要清理全部的 <code>*.jpg</code> 文件，只需要如下命令，需要注意的是这样也会把项目中现有的所有 <code>.jpg</code> 文件清理掉。</p>
<figure data-rehype-pretty-code-figure=""><pre tabindex="0" data-language="text" data-theme="solarized-light gruvbox-dark-medium"><code data-language="text" data-theme="solarized-light gruvbox-dark-medium" style="display: grid;"><span data-line=""><span>git filter-repo --path-glob '*.jpg' --invert-paths</span></span>
<span data-line=""> </span>
<span data-line=""><span>之后，强制推送到远程👇</span></span>
<span data-line=""> </span>
<span data-line=""><span>git push --all --force</span></span>
<span data-line=""> </span>
<span data-line=""><span>git push --tags --force</span></span></code></pre></figure>
<p>废了一些功夫，效果一级棒👍
<img src="2.png" alt="" title="清理前">
<img src="3.png" alt="" title="清理后"></p>
<p>参考链接：</p>
<ul>
<li><a href="https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E9%87%8D%E5%86%99%E5%8E%86%E5%8F%B2">Git-工具-重写历史</a></li>
<li><a href="https://github.com/newren/git-filter-repo/blob/main/INSTALL.md">git-filter-repo</a></li>
</ul>]]></content:encoded>
            <category>git</category>
        </item>
        <item>
            <title><![CDATA[面经记录]]></title>
            <link>https://mylofi.fun/posts/interview/</link>
            <guid isPermaLink="false">https://mylofi.fun/posts/interview/</guid>
            <pubDate>Wed, 13 Jul 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[记录疫情解封后的一次面试题]]></description>
            <content:encoded><![CDATA[<h3 id="vue-相关"><a href="#vue-相关">vue 相关</a></h3>
<ul>
<li><code>mixin</code> 相关场景以及利弊，拥有多个属性时的执行顺序，</li>
<li><code>v-model</code> 原理，在下拉选择器组件中是怎么实现的</li>
<li><code>filter</code> 怎么实现，使用场景</li>
<li>插槽的实现原理，如何传值</li>
<li><code>v-for</code> 中 <code>key</code> 的作用，延伸到 <code>diff</code> 实现，不同位置的比较</li>
<li><code>vnode</code> 概念</li>
<li><code>v-if</code> 控制 <code>dom</code> 显隐时， <code>vdom</code> 是如何处理的</li>
<li><code>watch</code> 监听是的 <code>deep: true</code> 实现原理</li>
<li><code>nextTick</code> 原理</li>
<li><code>computed</code> 和 <code>watch</code> 的区别</li>
<li><code>Vue.use</code> 和 <code>Vue.install</code></li>
<li><code>Vue</code> 中手动 <code>extend</code></li>
<li><code>data</code> 中的属性是定义在 <code>MVVM</code> 中的哪个环节</li>
</ul>
<h3 id="css-相关"><a href="#css-相关">css 相关</a></h3>
<ul>
<li>回流和重绘的概念，绝对定位是否会导致回流</li>
<li><code>flex: 1</code> 的分别代表什么属性以及作用</li>
<li>伪元素和伪类的区别，分别有哪些</li>
<li><code>visibility: hidden</code> 和 <code>opacity</code> 是否触发点击事件</li>
</ul>
<h3 id="js-相关"><a href="#js-相关">js 相关</a></h3>
<ul>
<li><code>let/const/var</code> 区别，用 <code>const</code> 声明对象时，是否可以改变对象的属性值，为什么</li>
<li>深度优先搜索和广度优先搜索</li>
<li>如何证明 <code>js</code> 对象里存在循环引用</li>
<li>类型判断的方法，<code>typeof</code> 对象的类属性</li>
<li>实例对象是否是 <code>Function</code> ，<code>instanceof Function</code> 结果</li>
<li><code>promise</code> 执行顺序，事件循环</li>
<li><code>es5</code> 模拟 <code>class</code> 的实现</li>
<li><code>localStorage</code> 如何实现过期时间</li>
<li>手机号正则</li>
</ul>
<h3 id="工程化相关"><a href="#工程化相关">工程化相关</a></h3>
<ul>
<li>介绍 <code>webpack</code> 常用的配置以及功能</li>
<li><code>webpack</code> 多页面有多个入口时如何配置</li>
<li><code>source-map</code> 分类，如何配置和调试</li>
<li><code>webpack</code> 中怎么隔离 <code>css</code></li>
<li>性能优化方案，代码/打包/资源加载方面</li>
<li>热更新原理</li>
</ul>
<h3 id="概念类问题"><a href="#概念类问题">概念类问题</a></h3>
<ul>
<li><code>http/https</code> 区别</li>
<li>介绍 <code>options</code> 请求的意义</li>
<li><code>MVVM/MVC</code> 的区别，如何实现一个 <code>MVVM</code></li>
<li>简述 <code>XSS</code> 和 <code>CSRF</code> 的概念，并列举几种安全防范策略</li>
</ul>
<h3 id="编程题"><a href="#编程题">编程题</a></h3>
<ul>
<li>编写一个函数，大小写字母取反</li>
</ul>
<figure data-rehype-pretty-code-figure=""><pre tabindex="0" data-language="javascript" data-theme="solarized-light gruvbox-dark-medium"><code data-language="javascript" data-theme="solarized-light gruvbox-dark-medium" style="display: grid;"><span data-line=""><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit">const</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F"> fn</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> =</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984"> (</span><span style="--shiki-light:#657B83;--shiki-dark:#83A598">string</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">)</span><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit"> =></span><span style="--shiki-light:#657B83;--shiki-dark:#A89984"> {</span></span>
<span data-line=""><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit">  let</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> ans</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> =</span><span style="--shiki-light:#2AA198;--shiki-dark:#A89984"> ''</span></span>
<span data-line=""><span style="--shiki-light:#859900;--shiki-dark:#FB4934">  for</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2"> (</span><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit">let</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> v</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> of</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> string</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">) </span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">{</span></span>
<span data-line=""><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">    ans</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> +=</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> v</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F">toLowerCase</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">() </span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C">===</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> v</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> ?</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> v</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F">toUpperCase</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">() </span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C">:</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> v</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F">toLowerCase</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">()</span></span>
<span data-line=""><span style="--shiki-light:#657B83;--shiki-dark:#A89984">  }</span></span>
<span data-line=""><span style="--shiki-light:#859900;--shiki-dark:#FB4934">  return</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> ans</span></span>
<span data-line=""><span style="--shiki-light:#657B83;--shiki-dark:#A89984">}</span></span></code></pre></figure>
<ul>
<li>编写一个函数，输入 <code>int</code> 型，返回整数逆序后的字符串</li>
<li>二维数组扁平化，返回一个去重且是升序的一维数组</li>
</ul>
<h3 id="场景题"><a href="#场景题">场景题</a></h3>
<ul>
<li>数据多、加载慢的解决方式
<ul>
<li>缓存</li>
<li>懒加载</li>
</ul>
</li>
<li>生产环境发布后，发现客户那边并没有更新到最新版，从哪些方面排查？
<ul>
<li>时间戳保持最新</li>
<li>强缓存/协商缓存</li>
<li>禁止缓存</li>
</ul>
</li>
<li><code>axios</code> 需要对所有接口进行增加请求头之类的字段时，怎么处理？</li>
<li>一个按钮含有异步请求，如何防止多次点击重复提交？
<ul>
<li>防抖及其实现，引申节流，描述区别及使用场景</li>
<li>增加禁用属性，<code>loading/disabled</code></li>
</ul>
</li>
<li>a 页面跳转到 b 页面然后重定向到 c 页面，可能会在 b 页面做登录逻辑或者记录数据（相当于一个中转页），
但是用户可能直接在地址栏里输入 c 页面，怎么防止这个情况？
<ul>
<li>路由守卫</li>
<li>导航拦截如何实现</li>
</ul>
</li>
<li>同一个浏览器，不同标签之间数据传递的方法，简单列举</li>
</ul>
<h3 id="发散性问题"><a href="#发散性问题">发散性问题</a></h3>
<ul>
<li>职业规划</li>
<li>怎么制定技术方案，从哪几个方面考虑</li>
</ul>]]></content:encoded>
            <category>笔记</category>
        </item>
        <item>
            <title><![CDATA[算法之深度优先搜索与广度优先搜索]]></title>
            <link>https://mylofi.fun/posts/dfs-bfs/</link>
            <guid isPermaLink="false">https://mylofi.fun/posts/dfs-bfs/</guid>
            <pubDate>Thu, 07 Jul 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[深度优先与广度优先的概念和区别]]></description>
            <content:encoded><![CDATA[<h3 id="深度优先搜索-dfs"><a href="#深度优先搜索-dfs">深度优先搜索 DFS</a></h3>
<p>深度优先搜索（Depth-First-Search）和广度优先搜索（Breadth-First-Search）都是一种用来遍历或者搜索树或图这种数据结构的算法。以树为例，深度优先搜索的过程会从根节点出发，尽可能深地遍历每个子节点，而且每个节点只能访问一次，是一个不断回溯的过程。</p>
<p>实现方法大致如下：</p>
<ol>
<li>首先将根节点放入栈中</li>
<li>从栈中取出第一个节点，并检验它是否为目标
<ol>
<li>如果找到目标，则结束搜索并返回结果</li>
<li>否则将它某一个尚未检验过的直接子节点放入栈中</li>
</ol>
</li>
<li>重复步骤 2</li>
<li>如果不存在未检测过的直接子节点
<ol>
<li>将上一级节点放入栈中</li>
<li>重复步骤 2</li>
</ol>
</li>
<li>重复步骤 4</li>
<li>若栈为空，表示整张图都已检查过并且没有要查找的目标，结束搜索</li>
</ol>
<p>另外需要我们了解的一种数据结构：栈。</p>
<p>我们可以把盏比喻成一包手帕纸，每张纸巾都是按序一张一张放进去的，使用的时候是一张一张从最上边开始拿出来的。所以栈是一种后进先出（Last In First Out, LIFO）的数据结构。</p>
<p><img src="dfs.png?width=50%22%E6%B7%B1%E5%BA%A6%E4%BC%98%E5%85%88%E6%90%9C%E7%B4%A2%22" alt=""></p>
<p>示例：通过 DFS 实现复制对象的复制</p>
<figure data-rehype-pretty-code-figure=""><pre tabindex="0" data-language="javascript" data-theme="solarized-light gruvbox-dark-medium"><code data-language="javascript" data-theme="solarized-light gruvbox-dark-medium" style="display: grid;"><span data-line=""><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit">const</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F"> copyDFS</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> =</span><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit"> function</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">(</span><span style="--shiki-light:#657B83;--shiki-dark:#83A598">obj</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">)</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984"> {</span></span>
<span data-line=""><span style="--shiki-light:#859900;--shiki-dark:#FB4934">  if</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2"> (</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">obj</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> ===</span><span style="--shiki-light:#B58900;--shiki-dark:#D3869B"> null</span><span style="--shiki-light:#859900;--shiki-dark:#FB4934"> ||</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> typeof</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> obj</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> !==</span><span style="--shiki-light:#2AA198;--shiki-dark:#A89984"> "</span><span style="--shiki-light:#2AA198;--shiki-dark:#B8BB26">object</span><span style="--shiki-light:#2AA198;--shiki-dark:#A89984">"</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">) </span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">{</span></span>
<span data-line=""><span style="--shiki-light:#859900;--shiki-dark:#FB4934">    return</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> obj</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">;</span></span>
<span data-line=""><span style="--shiki-light:#657B83;--shiki-dark:#A89984">  }</span></span>
<span data-line=""><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit">  const</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> copyObj</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> =</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> Array</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F">isArray</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">(</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">obj</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">) </span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C">?</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2"> [] </span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C">:</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984"> {};</span></span>
<span data-line=""><span style="--shiki-light:#859900;--shiki-dark:#FB4934">  for</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2"> (</span><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit">const</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> key</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> in</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> obj</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">) </span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">{</span></span>
<span data-line=""><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">    copyObj</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">[</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">key</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">] </span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C">=</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F"> copyDFS</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">(</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">obj</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">[</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">key</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">])</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">;</span></span>
<span data-line=""><span style="--shiki-light:#657B83;--shiki-dark:#A89984">  }</span></span>
<span data-line=""><span style="--shiki-light:#859900;--shiki-dark:#FB4934">  return</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> copyObj</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">;</span></span>
<span data-line=""><span style="--shiki-light:#657B83;--shiki-dark:#A89984">}</span></span></code></pre></figure>
<p>示例：获取对象的所有键</p>
<figure data-rehype-pretty-code-figure=""><pre tabindex="0" data-language="javascript" data-theme="solarized-light gruvbox-dark-medium"><code data-language="javascript" data-theme="solarized-light gruvbox-dark-medium" style="display: grid;"><span data-line=""><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit">const</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> obj</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> =</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984"> {</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2"> a</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">:</span><span style="--shiki-light:#D33682;--shiki-dark:#D3869B"> 1</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">,</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2"> b</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">:</span><span style="--shiki-light:#D33682;--shiki-dark:#D3869B"> 2</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">,</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2"> c</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">:</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984"> {</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2"> d</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">:</span><span style="--shiki-light:#D33682;--shiki-dark:#D3869B"> 4</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">,</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2"> e</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">:</span><span style="--shiki-light:#D33682;--shiki-dark:#D3869B"> 5</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">}</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984"> }</span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit">function</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F"> dfs</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">(</span><span style="--shiki-light:#657B83;--shiki-dark:#83A598">obj</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">,</span><span style="--shiki-light:#657B83;--shiki-dark:#83A598"> keys</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> =</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2"> []</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">)</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984"> {</span></span>
<span data-line=""><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">  Object</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F">entries</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">(</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">obj</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">)</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F">forEach</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">(</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">([</span><span style="--shiki-light:#657B83;--shiki-dark:#83A598">k</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">,</span><span style="--shiki-light:#657B83;--shiki-dark:#83A598"> v</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">])</span><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit"> =></span><span style="--shiki-light:#657B83;--shiki-dark:#A89984"> {</span></span>
<span data-line=""><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">    keys</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F">push</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">(</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">k</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">)</span></span>
<span data-line=""><span style="--shiki-light:#859900;--shiki-dark:#FB4934">    if</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2"> (</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C">typeof</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> v</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> ===</span><span style="--shiki-light:#2AA198;--shiki-dark:#A89984"> '</span><span style="--shiki-light:#2AA198;--shiki-dark:#B8BB26">object</span><span style="--shiki-light:#2AA198;--shiki-dark:#A89984">'</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">) </span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F">dfs</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">(</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">v</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">,</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> keys</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">)</span></span>
<span data-line=""><span style="--shiki-light:#859900;--shiki-dark:#FB4934">    else</span><span style="--shiki-light:#859900;--shiki-dark:#FB4934"> return</span></span>
<span data-line=""><span style="--shiki-light:#657B83;--shiki-dark:#A89984">  }</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">)</span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#859900;--shiki-dark:#FB4934">  return</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> keys</span></span>
<span data-line=""><span style="--shiki-light:#657B83;--shiki-dark:#A89984">}</span></span>
<span data-line=""><span style="--shiki-light:#93A1A1;--shiki-light-font-style:italic;--shiki-dark:#928374;--shiki-dark-font-style:italic">// ['a', 'b', 'c', 'd', 'e', 'f']</span></span>
<span data-line=""><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">console</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F">log</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">(</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F">dfs</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">(</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">obj</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">))</span></span></code></pre></figure>
<h3 id="广度优先搜索-bfs"><a href="#广度优先搜索-bfs">广度优先搜索 BFS</a></h3>
<p>广度优先搜索（Breadth-First-Search）也会沿着树的宽度进行遍历，通常用来解决两种问题：</p>
<ul>
<li>从节点 A 出发，有前往节点 B 的路径吗？</li>
<li>从节点 A 出发，前往节点 B 的哪条路径最短？</li>
</ul>
<p><img src="bfs.png?width=50%22%E5%B9%BF%E5%BA%A6%E4%BC%98%E5%85%88%E6%90%9C%E7%B4%A2%22" alt=""></p>
<p>举个例子，假如今天的你心血来潮突然想看《假面骑士》，当你打开腾讯视频的时候发现只有会员才能看，真扫兴（胜利的法则变得不太确定）。这时你又不想自费充会员，所以就想找朋友借个用用。于是去挨个去问你的朋友，如果你的朋友里都没有会员，那就必须要找你朋友的朋友，别忘了你的目标是找来一个会员账号。首先，将你的朋友列入一个名单中依次查找，如果你的朋友李白没有会员，其次再将李白的朋友也加入到名单中，所以为了这个目标，你需要在你的朋友、朋友的朋友中查找，这种方式会搜遍你的整个人际关系网络，直到借来一个会员账号（胜利的法则已经决定✌️）或者一个会员都没有为止，这个过程就是广度优先搜索算法。</p>
<p>回到刚才的两个问题：</p>
<ul>
<li>从节点 A 出发，有前往节点 B 的路径吗？（在你的人际关系网中，有会员吗？）</li>
<li>从节点 A 出发，前往节点 B 的哪条路径最短？（哪个拥有会员的朋友和你的关系最近？）</li>
</ul>
<p>第一个问题已经在上例中说明；第二个问题就是怎么找到关系最近的朋友。</p>
<p>假设你的朋友是一层关系，朋友的朋友是二层关系。很显然，一层关系优于二层关系，二层关系优于三层关系，以此类推。需要注意的是，<strong>一层关系是在二层关系之前加入名单的</strong>，这就意味着我们依次对名单<strong>按照顺序</strong>进行查找出来的结果一定是关系最近的朋友，所以，广度优先搜索不仅查找 A 到 B 的路径，而且找到的是<strong>最短路径</strong>。</p>
<p>对于 BFS 算法，我们还需要了解另外一个数据结构：队列。</p>
<p>队列的工作原理和现实生活中的队列一样，假设你和朋友一起在排队买咖啡，如果你排在他前面，那就是你先买到咖啡。队列只支持两种操作：入队和出队，是一种先进先出（First In First Out, FIFO）的数据结构，</p>
<p>至此，我们可以使用队列来表示这份朋友名单，因为先加入的朋友（一层关系）将会先出队列并而且先被检查。</p>
<p>实现方法大致如下：</p>
<ol>
<li>首先将根节点放入队列中</li>
<li>从队列中取出第一个节点，并检查它是否为目标
<ol>
<li>如果找到目标，则结束搜索并返回结果</li>
<li>否则将它所有尚未检查过的子节点加入队列中</li>
</ol>
</li>
<li>若队列为空，表示整张图都检查过了，即没有查询的目标</li>
<li>重复步骤 2</li>
</ol>
<p>示例：通过 DFS 实现对象深拷贝：</p>
<figure data-rehype-pretty-code-figure=""><pre tabindex="0" data-language="javascript" data-theme="solarized-light gruvbox-dark-medium"><code data-language="javascript" data-theme="solarized-light gruvbox-dark-medium" style="display: grid;"><span data-line=""><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit">function</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F"> deepCopy</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">(</span><span style="--shiki-light:#657B83;--shiki-dark:#83A598">obj</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">)</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984"> {</span></span>
<span data-line=""><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit">  const</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> queue</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> =</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2"> [</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">obj</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">]</span></span>
<span data-line=""><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit">  const</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> newObject</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> =</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984"> {}</span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#859900;--shiki-dark:#FB4934">  while</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2"> (</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">queue</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#657B83;--shiki-dark:#D3869B">length</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> ></span><span style="--shiki-light:#D33682;--shiki-dark:#D3869B"> 0</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">) </span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">{</span></span>
<span data-line=""><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit">    const</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> currentObj</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> =</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> queue</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F">shift</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">()</span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">    Object</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F">keys</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">(</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">currentObj</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">)</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F">forEach</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">(</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">(</span><span style="--shiki-light:#657B83;--shiki-dark:#83A598">key</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">)</span><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit"> =></span><span style="--shiki-light:#657B83;--shiki-dark:#A89984"> {</span></span>
<span data-line=""><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit">      const</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> value</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> =</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> currentObj</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">[</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">key</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">]</span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#859900;--shiki-dark:#FB4934">      if</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2"> (</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C">typeof</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> value</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> ===</span><span style="--shiki-light:#2AA198;--shiki-dark:#A89984"> '</span><span style="--shiki-light:#2AA198;--shiki-dark:#B8BB26">object</span><span style="--shiki-light:#2AA198;--shiki-dark:#A89984">'</span><span style="--shiki-light:#859900;--shiki-dark:#FB4934"> &#x26;&#x26;</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> value</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> !==</span><span style="--shiki-light:#B58900;--shiki-dark:#D3869B"> null</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">) </span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">{</span></span>
<span data-line=""><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">        queue</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F">push</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">(</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">value</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">)</span></span>
<span data-line=""><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">        newObject</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">[</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">key</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">] </span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C">=</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> Array</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F">isArray</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">(</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">value</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">) </span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C">?</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2"> [] </span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C">:</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984"> {}</span></span>
<span data-line=""><span style="--shiki-light:#657B83;--shiki-dark:#A89984">      }</span><span style="--shiki-light:#859900;--shiki-dark:#FB4934"> else</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984"> {</span></span>
<span data-line=""><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">        newObject</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">[</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">key</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">] </span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C">=</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> value</span></span>
<span data-line=""><span style="--shiki-light:#657B83;--shiki-dark:#A89984">      }</span></span>
<span data-line=""><span style="--shiki-light:#657B83;--shiki-dark:#A89984">    }</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">)</span></span>
<span data-line=""><span style="--shiki-light:#657B83;--shiki-dark:#A89984">  }</span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#859900;--shiki-dark:#FB4934">  return</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> newObject</span></span>
<span data-line=""><span style="--shiki-light:#657B83;--shiki-dark:#A89984">}</span></span>
<span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit">const</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> obj</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> =</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984"> {</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2"> a</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">:</span><span style="--shiki-light:#D33682;--shiki-dark:#D3869B"> 1</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">,</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2"> b</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">:</span><span style="--shiki-light:#D33682;--shiki-dark:#D3869B"> 2</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984"> }</span></span>
<span data-line=""><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit">const</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> copy</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> =</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F"> deepCopy</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">(</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">obj</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">)</span></span>
<span data-line=""><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">copy</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">a</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> =</span><span style="--shiki-light:#D33682;--shiki-dark:#D3869B"> 3</span></span>
<span data-line=""><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">console</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F">log</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">(</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">copy</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">) </span><span style="--shiki-light:#93A1A1;--shiki-light-font-style:italic;--shiki-dark:#928374;--shiki-dark-font-style:italic">// {a: 3, b: 2}</span></span>
<span data-line=""><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">console</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F">log</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">(</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">copy</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> ===</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> obj</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">) </span><span style="--shiki-light:#93A1A1;--shiki-light-font-style:italic;--shiki-dark:#928374;--shiki-dark-font-style:italic">// false</span></span>
<span data-line=""> </span></code></pre></figure>]]></content:encoded>
            <category>算法</category>
        </item>
        <item>
            <title><![CDATA[Javascript 之原型链]]></title>
            <link>https://mylofi.fun/posts/prototype/</link>
            <guid isPermaLink="false">https://mylofi.fun/posts/prototype/</guid>
            <pubDate>Fri, 10 Jun 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[巩固复习一下 Javascript 原型链的知识]]></description>
            <content:encoded><![CDATA[<figure data-rehype-pretty-code-figure=""><pre tabindex="0" data-language="javascript" data-theme="solarized-light gruvbox-dark-medium"><code data-language="javascript" data-theme="solarized-light gruvbox-dark-medium" style="display: grid;"><span data-line=""> </span>
<span data-line=""><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit">function</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F"> SuperType</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">()</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984"> {</span></span>
<span data-line=""><span style="--shiki-light:#268BD2;--shiki-dark:#FE8019">  this</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">property</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> =</span><span style="--shiki-light:#B58900;--shiki-dark:#D3869B"> true</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">;</span></span>
<span data-line=""><span style="--shiki-light:#657B83;--shiki-dark:#A89984">}</span></span>
<span data-line=""><span style="--shiki-light:#859900;--shiki-dark:#EBDBB2">SuperType</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#657B83;--shiki-dark:#D3869B">prototype</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F">getSuperValue</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> =</span><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit"> function</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">()</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984"> {</span></span>
<span data-line=""><span style="--shiki-light:#859900;--shiki-dark:#FB4934">  return</span><span style="--shiki-light:#268BD2;--shiki-dark:#FE8019"> this</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">property</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">;</span></span>
<span data-line=""><span style="--shiki-light:#657B83;--shiki-dark:#A89984">}</span></span>
<span data-line=""><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit">function</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F"> SubType</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">()</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984"> {</span></span>
<span data-line=""><span style="--shiki-light:#268BD2;--shiki-dark:#FE8019">  this</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">subproperty</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> =</span><span style="--shiki-light:#B58900;--shiki-dark:#D3869B"> false</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">;</span></span>
<span data-line=""><span style="--shiki-light:#657B83;--shiki-dark:#A89984">}</span></span>
<span data-line=""><span style="--shiki-light:#93A1A1;--shiki-light-font-style:italic;--shiki-dark:#928374;--shiki-dark-font-style:italic">//  修改 SubType 的原型，重新指向 SuperType </span></span>
<span data-line=""><span style="--shiki-light:#859900;--shiki-dark:#EBDBB2">SubType</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#657B83;--shiki-dark:#D3869B">prototype</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> =</span><span style="--shiki-light:#859900;--shiki-dark:#FE8019"> new</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F"> SuperType</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">()</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">;</span></span>
<span data-line=""><span style="--shiki-light:#859900;--shiki-dark:#EBDBB2">SubType</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#657B83;--shiki-dark:#D3869B">prototype</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F">getSubValue</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> =</span><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit"> function</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">()</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984"> {</span></span>
<span data-line=""><span style="--shiki-light:#859900;--shiki-dark:#FB4934">  return</span><span style="--shiki-light:#268BD2;--shiki-dark:#FE8019"> this</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">subproperty</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">;</span></span>
<span data-line=""><span style="--shiki-light:#657B83;--shiki-dark:#A89984">}</span></span>
<span data-line=""><span style="--shiki-light:#586E75;--shiki-light-font-weight:bold;--shiki-dark:#FE8019;--shiki-dark-font-weight:inherit">let</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598"> instance</span><span style="--shiki-light:#859900;--shiki-dark:#8EC07C"> =</span><span style="--shiki-light:#859900;--shiki-dark:#FE8019"> new</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F"> SubType</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">()</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">;</span></span>
<span data-line=""><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">console</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F">log</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">(</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">instance</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F">getSuperValue</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">()) </span><span style="--shiki-light:#93A1A1;--shiki-light-font-style:italic;--shiki-dark:#928374;--shiki-dark-font-style:italic">// true</span></span>
<span data-line=""><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">console</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F">log</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">(</span><span style="--shiki-light:#268BD2;--shiki-dark:#83A598">instance</span><span style="--shiki-light:#657B83;--shiki-dark:#A89984">.</span><span style="--shiki-light:#268BD2;--shiki-dark:#FABD2F">getSubValue</span><span style="--shiki-light:#657B83;--shiki-dark:#EBDBB2">()) </span><span style="--shiki-light:#93A1A1;--shiki-light-font-style:italic;--shiki-dark:#928374;--shiki-dark-font-style:italic">// false</span></span>
<span data-line=""> </span></code></pre></figure>
<p><img src="2x.png" alt="" title="原型链"></p>]]></content:encoded>
            <category>Javascript</category>
        </item>
        <item>
            <title><![CDATA[深入了解现代网络浏览器（2/4）【译】]]></title>
            <link>https://mylofi.fun/posts/inside%20look%20at%20modern%20web%20browser-2/</link>
            <guid isPermaLink="false">https://mylofi.fun/posts/inside look at modern web browser-2/</guid>
            <pubDate>Sat, 28 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[一个通过翻译的方式学习英语的尝试计划]]></description>
            <content:encoded><![CDATA[<h2 id="导航栏里都发生了些什么"><a href="#导航栏里都发生了些什么">导航栏里都发生了些什么</a></h2>
<p>这是 4 篇博客系列中的第 2 篇，来窥探 Chrome 的内部工作原理。在<a href="https://flyingmylo.com/posts/inside-look-at-modern-web-browser-1/">上一篇文章</a>中，我们探讨了进程和线程在处理浏览器不同模块时的区别。本篇文章我们将会更深层次地挖掘线程和进程为了渲染一个网站是如何进行有序通信的。</p>
<p>我们来看一个浏览器里简单的例子：在浏览器中输入一个 URL 地址，接着浏览器会从网络中请求数据然后渲染出一个页面。在这篇文章中，我们将会聚焦于用户请求一个站点随后浏览器准备渲染页面这一部分，也就是我们熟知的导航。</p>
<h2 id="始于一个浏览器进程"><a href="#始于一个浏览器进程">始于一个浏览器进程</a></h2>
<p>正如我们已经在 <a href="https://flyingmylo.com/posts/inside-look-at-modern-web-browser-1/#%E4%B8%AD%E5%A4%AE%E5%A4%84%E7%90%86%E5%99%A8%E5%9B%BE%E5%BD%A2%E5%A4%84%E7%90%86%E5%99%A8%E5%86%85%E5%AD%98%E5%A4%9A%E8%BF%9B%E7%A8%8B%E6%9E%B6%E6%9E%84">上篇中阐述过的 GPU/CPU/内存/多进程架构</a> 一样，浏览器进程处理了其每个标签页的所有任务。浏览器进程拥有像 UI 线程这样绘制按钮或者输入框的进程，还有网络线程从网络中接收数据，存储线程控制文件的访问等等这些进程。当我们在地址栏中输入一个 URL 地址时，我们的输入就会被浏览器进程里的 UI 线程处理。
<img src="01.png" alt="" title="图1：上方是浏览器的用户界面，下方则是浏览器进程的示意图，其中包含了用户界面、网络和存储线程。"></p>
<h2 id="一个简单的导航"><a href="#一个简单的导航">一个简单的导航</a></h2>
<h3 id="第一步处理输入"><a href="#第一步处理输入">第一步：处理输入</a></h3>
<p>当用户开始在地址栏中输入的时候，UI 线程首要询问的是“这是一个搜索关键词还是一个地址咧？”。在 Chrome 中，地址栏同样是一个搜索框，所以 UI 线程需要解析并且决定是要把输入发送给搜索引擎，还是直接显示这个你请求的网站。
<img src="02.png" alt="" title="图2：UI 线程询问此输入是搜索关键字还是一个地址"></p>
<h3 id="第二步开始导航"><a href="#第二步开始导航">第二步：开始导航</a></h3>
<p>当用户敲了回车键，UI 线程会初始化一个网络命令去获取网站内容，此时在标签页的左上角会显示一个转圈圈的加载器 ，随后网络线程会通过合适的协议，比如 DNS 查询为该请求建立 TLS 链接。
<img src="03.png" alt="" title="图3：UI 线程与网络线程通信，以导航到 mysite.com 站点">
此时网络进程可能会收到一个服务器的重定向头信息，比如 HTTP 301 ，这种情况下，网络线程就会和 UI 线程对于服务器正在请求重定向进行通信，然后向另一个 URL 发起请求。</p>
<h3 id="第三步读取响应"><a href="#第三步读取响应">第三步：读取响应</a></h3>
<p>当响应正文开始返回的时候，网络线程就会在必要时查看字节流的前几个字节，响应头中的 Content-Type 字段说明了数据的类型，但是由于它可能会出错或是不准确，所以此处会有一个 <a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types">MIME Type Sniffing</a> 检查来确认该数据是什么类型。这算是 <a href="https://source.chromium.org/chromium/chromium/src/+/main:net/base/mime_sniffer.cc;l=5">源码</a> 中提到的一个“小花招”，具体可以参见文章中的注释以了解不同的浏览器是如何处理 <code>content-type/payload</code> 的。
<img src="04.png" alt="" title="图4：响应头包含了 Content-Type 用以说明数据类型，而 payload 表示真实传输的数据"></p>
<p>如果服务器返回的是一个 HTML 文件，那么下一步浏览器就会向渲染进程传递数据以渲染页面，但如果是一个 zip 文件或其他格式的文件，就意味着这是一个下载请求，此时浏览器需要把数据传递给下载管理器以下载文件。
<img src="05.png" alt="" title="图5：网络线程询问响应的数据是否是一个来自安全站点的 HTML"></p>
<p>这也正是 <a href="https://safebrowsing.google.com/">SafeBrowsing</a> 发生的时机。如果域名和响应数据看起来像个恶意的网站，这时网络线程会警惕性地显示一个提示页面，而且也会触发 <a href="https://www.chromium.org/Home/chromium-security/corb-for-developers/">Cross Origin Read Blcoking(CORB)</a> 检测，以确保被攻击的垮站数据不会被传递给渲染进程。</p>
<h3 id="第四步查找渲染器进程"><a href="#第四步查找渲染器进程">第四步：查找渲染器进程</a></h3>
<p>当所有的检测工作都已完成，并且网络线程也能够确信浏览器可以处理这个请求站点时，网络线程就会告诉 UI 线程数据已就绪，UI 线程就会寻找一个渲染器进程继续渲染这个网页。
<img src="06.png" alt="" title="图6：网络线程告诉 UI 线程去寻找一个渲染器进程">
由于网络请求可能需要几百毫秒才能获取到响应回复，因此需要对这个过程进行优化加速。在第二步的时候，当 UI 线程正在向网络线程发送一个 URL 请求，它就已经知道目标网站的地址了。同时 UI 线程会为这个网络请求试图主动查找或开启一个渲染器进程。这样一来，如果所有的步骤都如期进行，一个渲染器进程就会在网络线程收到数据的时候原定待命。如果导航发生跨站重定向的话，这个备用状态的进程可能不会被用到，此时可能就需要另外一个进程了。</p>
<h3 id="第五步委托导航"><a href="#第五步委托导航">第五步：委托导航</a></h3>
<p>现在数据和渲染器进程已经准备就绪，一个 IPC 信号（进程间通信 Inter-Process Communication，简称IPC，是一种技术或方法，用于在至少两个进程或线程之间传输数据或信号。每个进程都有自己独立的系统资源，彼此隔离。）会从浏览器进程发送到渲染器进程以委托这个导航。它也会传递数据流，这样渲染器进程就能一直收到 HTML 数据。当渲染器进程收到委托的信号一旦被浏览器进程回执确认后，这个导航就完成了，并且文档的加载阶段也随之开始。</p>
<p>与此同时，地址栏便会更新，安全指示器和网站设置的用户界面也会显示出新页面的网站信息。标签页的会话历史记录也会被更新，因此后退/前进按钮也会跳转到刚刚导航过的网站。为了方便在关闭标签页或窗口时恢复标签页/会话，会话历史记录会存储在磁盘上。
<img src="07.png" alt="" title="图7：浏览器进程和渲染器进程之间的通信，请求渲染此页面"></p>
<h3 id="附加步骤初始化加载完成"><a href="#附加步骤初始化加载完成">附加步骤：初始化加载完成</a></h3>
<p>一旦导航已提交，渲染器进程就会携带加载资源渲染这个页面。我们将会在下一篇文章中详细回顾在这一阶段发生的事情。当渲染器进程「完成」了渲染，它会发送一个 IPC 信号给浏览器进程（此举发生在所有页面的加载事件发出并且完成执行之后），此时 UI 线程便会停止标签页上的加载器。</p>
<p>我之所以说「完成」，是因为客户端 <code>JavaScript</code> 仍然可以在此之后加载其他资源并渲染新视图。
<img src="08.png" alt="" title="图8：从渲染器到浏览器进程的 IPC 信号，通知页面已经完成加载"></p>
<h2 id="导航到一个不同的网站"><a href="#导航到一个不同的网站">导航到一个不同的网站</a></h2>
<p>这个简单的导航已经完成！但是，如果用户在地址栏中再次输入不同的 URL，会发生什么情况呢？那么，浏览器进程会通过相同的步骤导航到不同的网站。但在此之前，它需要检查当前渲染的网站是否关心 <code>beforeunload</code> 事件。</p>
<p>当你尝试离开或者关闭当前标签页的时候，<code>beforeunload</code> 事件可以创造一个“是否离开当前网站”的弹窗提示。一个标签页内部的所有内容包含你的<code>JavaScript</code> 代码，都由渲染器进程处理，所以当一个新的导航请求到来时，浏览器进程必须检查当前的渲染器进程。</p>
<blockquote>
<p>⚠️注意：不要添加无条件的 <code>beforeunload</code> 处理事件。它会产生更多延迟，因为处理事件需要在导航开始之前被执行。这个事件处理器只应该在被需要的时候添加，比如，当用户需要被提醒警告他们可能会丢失已经在当前页面输入的数据。</p>
</blockquote>
<p><img src="09.png" alt="" title="图9：浏览器进程发送 IPC 信号给渲染器进程，告知它将会导航到一个新的网站"></p>
<p>If the navigation was initiated from the renderer process (like user clicked on a link or client-side JavaScript has run window.location = "<a href="https://newsite.com">https://newsite.com</a>") the renderer process first checks beforeunload handlers. Then, it goes through the same process as browser process initiated navigation. The only difference is that navigation request is kicked off from the renderer process to the browser process.</p>
<p>When the new navigation is made to a different site than currently rendered one, a separate render process is called in to handle the new navigation while current render process is kept around to handle events like unload. For more, see an overview of page lifecycle states and how you can hook into events with the Page Lifecycle API.</p>]]></content:encoded>
            <category>翻译</category>
        </item>
        <item>
            <title><![CDATA[深入了解现代网络浏览器（1/4）【译】]]></title>
            <link>https://mylofi.fun/posts/inside%20look%20at%20modern%20web%20browser-1/</link>
            <guid isPermaLink="false">https://mylofi.fun/posts/inside look at modern web browser-1/</guid>
            <pubDate>Wed, 18 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[一个通过翻译的方式学习英语的尝试计划]]></description>
            <content:encoded><![CDATA[<blockquote>
<p>📌 本篇原文发表于 2018.09.05，正文中出现的有关于时间概念的语句，阅读时请注意切换语境。 👉🏻<a href="https://developer.chrome.com/blog/inside-browser-part1">原文链接</a></p>
</blockquote>
<h2 id="中央处理器图形处理器内存多进程架构"><a href="#中央处理器图形处理器内存多进程架构">中央处理器/图形处理器/内存/多进程架构</a></h2>
<p>在这个包含 4 篇文章的博客系列中，我们将从高阶架构到具体的渲染细节来深入 Chrome 浏览器内部了解其是怎么运作的。如果你曾经好奇浏览器是怎么把代码转变成一个功能齐备的网站，或者你并不确定为什么一个具体的技术细节能够带来性能提升，那么这个系列正好是为你准备的。</p>
<p>作为系列第一篇，我们将会了解一些核心的计算机术语和 Chrome 浏览器的多进程架构。如果你对 CPU/GPU 和 进程/线程已经很熟悉，可以直接跳到 <a href="https://www.notion.so/1-4-f99425f08f0c427480b1b87116613422">浏览器架构</a> 章节。</p>
<h2 id="计算机的核心---cpu-和-gpu"><a href="#计算机的核心---cpu-和-gpu">计算机的核心 - CPU 和 GPU</a></h2>
<blockquote>
<p>为了理解浏览器所运行的环境，我们需要先了解计算机的一些部件以及它们是做什么的。</p>
</blockquote>
<h3 id="中央处理器-cpu"><a href="#中央处理器-cpu">中央处理器 CPU</a></h3>
<p>首先是中央处理器（CPU, Central Processing Unit）。CPU 可以被看作是一台计算机的大脑，一个 CPU 内核可以想象成一位办公室工作人员，能够处理一个接一个被安排的多个任务，可以处理一切从数学甚至到艺术领域的难题，而且它知道如何去响应一个用户的指令。以前的大多数 CPU 都是单个芯片，一个内核就相当于是一个 CPU 被嵌入到一个芯片上。在现代的硬件条件下，出现了多核处理器，也赋予了手机、笔记本更强的计算能力。</p>
<p><img src="figure-1.png" alt="" title="图 1：四个 CPU 内核就像彼此相邻的办公室职员一样处理多个任务"></p>
<h3 id="图形处理器-gpu"><a href="#图形处理器-gpu">图形处理器 GPU</a></h3>
<p>图形处理器是计算机里的另一个部件。和 CPU 不同的是，GPU 更擅长在多核之间处理一些简单的任务。顾名思义，GPU 最初是被开发成处理图形任务的模块，这也是为什么在很多图形计算的背景下，会把“使用 GPU”或“支持 GPU”和快速渲染、流畅的交互体验相关联在一起。近些年来，有了 GPU 加速的计算能力，也使 GPU 独立承载越来越多的计算成为可能。</p>
<p><img src="figure-2.webp" alt="" title="图2：多个带着扳手🔧️的 GPU 内核，表明它们只能处理有限的任务"></p>
<p>当你在手机或电脑上启动一个应用时，是 CPU 和 GPU 在给应用提供运行能力。通常情况下，操作系统提供了一套运行机制供应用程序在 CPU 和 GPU 运行。</p>
<p><img src="figure-3.webp" alt="" title="图 3: 计算机的三层架构示意图；机械硬件在最底层，操作系统在中间层，应用程序在最上层"></p>
<h2 id="在进程和线程里执行程序"><a href="#在进程和线程里执行程序">在进程和线程里执行程序</a></h2>
<p><img src="figure-4.webp" alt="" title="图 4: 进程就像一个鱼缸，线程就像鱼儿🐟️在鱼缸里游泳🏊🏻‍♀️"></p>
<p>在深入了解浏览器架构之前，另一个需要掌握的概念是 <strong>进程</strong> 和 <strong>线程</strong>。一个进程可以被看作是一个应用的执行程序，线程不仅是进程的一部分，而且可以执行其所在进程里的任意部分的程序代码。</p>
<p>当启动一个应用时，就等于创建了一个进程。程序可能会创建一个或多个线程来保障其正常工作，当然也可能不会创建。操作系统为进程提供了一个内存管理器，所有的应用状态都被保存在私密的内存空间中，当应用被关闭的时候，该进程也相应消失，同时操作系统也会释放内存。</p>
<p><img src="/images/figure-5.svg" alt="" title="图 5: 进程使用内存空间存储应用数据"></p>
<p>一个进程可以请求让操作系统去启动另外一个进程以运行不同的任务，如此一来，不同的内存空间也会被分配给新的进程。不同的进程之间可以通过 <strong>IPC</strong> (进程间通信 <strong>I</strong>nter <strong>P</strong>rocess <strong>C</strong>ommunication) 进行通信，许多应用都是使用这种设计方式开发的，以便于当一个工作进程没有响应的时候，该进程可以在不影响其他进程的情况下重新启动。</p>
<p><img src="/images/figure-6.svg" alt="" title="图 6: 不同的进程之间通过 IPC 进行通信"></p>
<h2 id="浏览器架构"><a href="#浏览器架构">浏览器架构</a></h2>
<p>那么现代浏览器是如何利用进程和线程构建的呢？好吧 =。= 可能是一个进程和很多个不同的线程，也可能是很多不同的进程和一些通过 IPC 通信的线程。</p>
<p><img src="figure-7.webp" alt="" title="图 7:  进程与线程间的不同浏览器架构"></p>
<p>需要注意的一个重要信息是，这些不同的架构主要是实现上的细节，构建一个浏览器并没有标准的规范，一个浏览器的实现方式也可能和其他的浏览器完全不同。</p>
<p>在本博客系列中，我们将用下文中的图示来描述 Chrome 浏览器最近更新的的架构。</p>
<p>图中最上层是浏览器进程在统一协调其他进程，它们分别负责应用程序内不同模块的代码执行。对于渲染器进程来说，它会创建多个进程并将其分配给每一个标签页，直到最近，Chrome 会在可能的情况下会给每个标签页分配一个进程；现在，Chrome 正在尝试着给每一个站点分配它自己的进程，包括 iframes（查看 <a href="https://www.notion.so/1-4-f99425f08f0c427480b1b87116613422">网站隔离</a>）。</p>
<p><img src="figure-8.webp" alt="" title="图 8: Chrome 的多进程架构示意图。可以看到渲染器进程下是有多个层级的，也表明着 Chrome 在每个标签页中执行着多个渲染器进程"></p>
<h2 id="不同的进程及其功能"><a href="#不同的进程及其功能">不同的进程及其功能</a></h2>
<table>
<thead>
<tr>
<th>进程</th>
<th>功能</th>
</tr>
</thead>
<tbody>
<tr>
<td>浏览器进程</td>
<td>控制 Chrome 浏览器应用本身，包括地址栏、书签、返回和前进按钮。同时也处理网页浏览器中那些看不到的、比较特殊的任务，比如网络请求和文件访问等</td>
</tr>
<tr>
<td>渲染器进程</td>
<td>控制标签页中一个网页显示的所有内容</td>
</tr>
<tr>
<td>插件进程</td>
<td>控制网页中使用的插件，比如 flash</td>
</tr>
<tr>
<td>GPU 进程</td>
<td>和其他进程相对独立，负责处理图形任务。GPU 进程会被划分为不同的进程，因为它会处理多个应用程序的请求并把它们绘制到同一个界面上。</td>
</tr>
</tbody>
</table>
<p><img src="figure-9.webp" alt="" title="图 9: 不同的进程负责浏览器界面的不同部分"></p>
<p>还有很多像扩展和通用的进程。如果你想要查看在 Chrome 中运行了多少进程，可以依次点击右上角的「**···**选项」菜单 →「更多工具」→「任务管理」，之后会打开一个窗口，显示当前运行进程的列表和 CPU 及内存的占用情况。</p>
<h2 id="chrome-浏览器中多进程的优势"><a href="#chrome-浏览器中多进程的优势">Chrome 浏览器中多进程的优势</a></h2>
<p>上文中，我们提到 Chrome 使用了多个渲染器进程。举个最简单的例子来讲，你可以想象一下每个标签页都有自己的渲染器进程，让我们假设你已经打开了 3 个标签页，而且每个标签页都由一个独立的渲染器进程负责运行，这时如果其中一个标签页没有响应或是卡死，那你可以关闭这个无响应的页面，同时还能保证其他页面正常运行。但如果所有的标签页都运行在同一个进程上，当有其中一个页面无响应时，那所有的页面也都会死翘翘，着实令人难过。🥲</p>
<p><img src="figure-10.webp" alt="" title="图 10: 每个标签页运行多个进程"></p>
<p>将浏览器的工作分离成多个进程的另一个好处是安全和沙盒化。由于操作系统提供了一种限制进程的方法，浏览器可以对某些进程进行沙盒化处理，使其与某些功能隔离起来。例如，浏览器限制了任意用户的输入进程对访问文件的权限，就像渲染器进程一样。</p>
<p>由于进程都有自己私有的内存空间，它们通常包含了一些通用基础架构的副本（如 V8 ， Chrome 的 JS 引擎）。这意味着会有更多的内存占用，因为它们不能像在同一进程中的线程那样共享。为了节省内存，Chrome 限制了它可以启动的进程数量，限制的进程数取决于设备的内存大小和 CPU 功率，当到达了限制数的上限时，它就会开始将同一站点的多个标签页运行在一个进程上。</p>
<h2 id="节省更多内存---chrome-中的服务化"><a href="#节省更多内存---chrome-中的服务化">节省更多内存 - Chrome 中的服务化</a></h2>
<p>浏览器进程的实现方式是大致相同的。Chrome 正在改变它的架构，将浏览器程序的每个部分作为服务运行，从而可以轻松地将浏览器的各个模块拆分为不同的进程或者聚合为一个进程。</p>
<p>通常情况下，当 Chrome 运行在一个配置强悍的硬件上时， 它可能会将每个服务分离成不同的进程，以获取更好的稳定性，但是如果是一台配置有限的设备上，Chrome 会为了节省内存占用将服务合并为一个进程。这与之前安卓平台的实现方式大同小异，都是通过合并进程来换来更少的内存占用。</p>
<p><img src="/images/figure-11.svg" alt="" title="图 11: Chrome 将不同的服务转化为多个进程和一个浏览器进程"></p>
<h2 id="单个-frame-渲染器进程---网站隔离"><a href="#单个-frame-渲染器进程---网站隔离">单个 frame 渲染器进程 - 网站隔离</a></h2>
<p><a href="https://developers.google.com//web/updates/2018/07/site-isolation">网站隔离</a> 是 Chrome 最近介绍的一项新功能，该功能可以为每一个跨域的 iframe 运行一个单独的渲染器进程。我们已经阐述过单个标签页对应单个渲染器进程的模式，这种模式允许跨域的 iframe 运行在一个单独的渲染器进程里，同时和其他网站共享内存空间。这也使得在同一个渲染器进程里运行 <a href="http://a.com">a.com</a> 和 <a href="http://b.com">b.com</a> 看起来是没什么问题的。<a href="https://developer.mozilla.org/docs/Web/Security/Same-origin_policy">同源策略</a> 是浏览器里核心的安全模型，它保证了一个网站不能在没有获取另一个网站的允许下访问该网站的数据。绕过这个策略是很多攻击网站安全的主要目标，而进程隔离是隔离网站最有效的方式，有了 <a href="https://developers.google.com/web/updates/2018/02/meltdown-spectre">幽灵漏洞</a> ，可以更明显地意识到，我们需要使用进程来隔离网站。自从 Chrome 67 之后，默认情况下隔离功能是开启的，这样一来，每个跨域的网站都会有一个单独的渲染器进程。</p>
<p><img src="figure-12.webp" alt="" title="图 12: 网站隔离，一个网页中有多个渲染器进程指向 iframe"></p>
<p>支持网站隔离功能是开发者多年以来努力的成果，网站隔离并不像合并多个不同的渲染器进程那样简单，它从根本上改变了 iframes 之间相互通信的方式。在不同进程中运行 iframe 的页面上打开 devtools，意味着 devtools 不得不执行一些幕后工作，才能使其看起来像无缝衔接。甚至是一个简单的 Ctrl+F 查找功能都要横跨数个不同的渲染器进程进行搜索。现在你能明白为什么浏览器开发工程师们说网站隔离的发布可以看作是一个里程碑的实现了吧！（哈哈哈真不容易🤓）。</p>
<h2 id="总结"><a href="#总结">总结</a></h2>
<p>本篇文章中，我们已经介绍了从高阶视角来看待浏览器架构和多进程架构的优势，还涉及到了 Chrome 中与多进程架构有深深关联的服务化和网站隔离。在下一篇文章中，我们将开始深入了解使网站呈现出来时，进程和线程之间都发生了什么事情。</p>
<p>下一篇：导航栏里发生了什么事情？</p>]]></content:encoded>
            <category>翻译</category>
            <category>英语</category>
        </item>
        <item>
            <title><![CDATA[普通的人]]></title>
            <link>https://mylofi.fun/posts/common-people/</link>
            <guid isPermaLink="false">https://mylofi.fun/posts/common-people/</guid>
            <pubDate>Fri, 27 Dec 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[一次胡思乱想的记录：相对于大城市里的生活，反而小城镇里的人们更有使命感]]></description>
            <content:encoded><![CDATA[<p>时间一天天过，烦恼一天天也不会缺席。同龄的朋友都挺羡慕我现在的状态，不急不慢地过着自己有节奏的生活，也有人说我过的很肆意、有趣，其实也挺没劲的，只是一个普通的上班族。在我看来只是不去想太多而已，只想享受当下的时光。那些到了年龄就该谈恋爱、买房成家的事情，我没想过，起码暂时是这样。</p>
<p>越长大越觉得自己只是一个普普通通的人，没有了以前的那种向往和憧憬，要成为一个多么厉害的人或是活得多么精彩，其实只是和公交司机、环卫工人、早餐店里奔跑的老爸一样的普通人。也越来越只想做一个普通人，没什么宏大的理想，做条咸鱼，养活自己和家人，也会为了生活四处奔波，和伴侣一起体验柴米油盐酱醋茶的平凡日子，想想其实也挺好，待在小城市里生长老去，消磨时光，如果能让时光变得更有意义就算是我幸运了吧。2019年有很多事情，工作或生活上的，都让我想了很多，想象以后的生活会是怎样的，同时也在困惑着我。《This Is Us》里有句台词这么说：「相对于大城市里的生活，反而小城镇里的人们更有使命感」，这句话让我深思了很久，一直想不太明白所谓的「使命感」到底是什么意思，现在也不得其解。城里的人向往城外的世界，城外的人羡慕城里的生活，其实是非常简单的一道选择题，但很需要勇气。而我一个普普通通的人整天都在做着不同的选择，并不会破坏社会秩序或是地球自转。</p>
<p>七月，提了离职。那段时间比较焦虑，焦虑原因是想的太多，诸如成家立业、娶妻生子，面临回老家还是留杭的选择。突然就意识到自己不是一个求学时的孩子而是一个真正的成年人，该面对的始终会来，不想逃避，但不愿给自己太大压力，只想出去来趟旅行，看看世界认识自己，换个心情再出发。九月，与友结伴去青海甘肃转了一个环线，途中碰到老乡同行也是巧合算是缘分。城外的模样是需要我们自己去看去听去感受的，一路上的那些朝圣者、放牧者、骑行者，他们都是为了某种意义而活吧，也不由得就想到了自己，这个谜题大概还没有答案。其实在某方面，有个出远门的机会我也是挺期待的，这也致使我非常享受此趟旅行带来的愉悦和舒畅，喜欢蓝天白云下的新鲜空气，喜欢迎面吹来的秋风，喜欢那种自由奔跑的感觉，喜欢在路上看着眼前的一切朝着反方向飞去，什么都不用想，烦恼杂事都抛在脑后，全身心的感受世界，听着喜欢的音乐，放空自己，就陶醉在美妙的大自然里。</p>
<p>回杭，重返到霓虹城市里的生活。日子又开始一天天过，开始求职之路，但是一切并没有想象中的那么顺利，此时面临的是一阵互联网公司裁员，行情很糟，心里始终吊着一块大石头，当然也在责怪自己之前的任性。起初自己心态还算良好乐观，只是随着时间的无情，工作一天不落地，心里也就不踏实。也逐渐意识到生活不易，意识到社会职场的残酷。想起来杭时在第一家公司辞职时的辞职信还是这样写：<strong>如果可以把生活比作一首歌，那我偏爱摇滚乐</strong>。直接 email 给了 leader 和 hr ，简直年少轻狂。为了打发求职期间的无聊，就买了把吉他，初衷是喜欢音乐，想学会弹奏自己喜欢的歌，虽然报了吉他社，但大多时间还是在自学。后来入职了新公司，手指的按弦难度加上新工作的加班，至此，初衷已经被劝退大半了。</p>
<p>生在北方，住在南方。自从收拾好了行囊开始出发，初衷也随着年龄的增长一点点在变，开始的雄心壮志到如今的思考人生。有时候也会在想，自己独身漂泊在外是为了寻求什么吗？现在想这个问题我也没有答案，是在寻求什么...形形色色的各式人种为了各自的目标去劳动、获得，循环往复地推进着这套系统的运行。我只是一个渺小的、闲下来就喜欢daydreaming 的生物细胞分子，无足轻重。也许慢慢地我也会寻到自己的方向，有自己的生活哲学，如果可以奢侈点，希望这一天能早些到来，即使付出成倍年龄，我始终也会做一颗会思考的芦苇。</p>
<p>2020 Be well :-)</p>]]></content:encoded>
            <category>随笔</category>
        </item>
        <item>
            <title><![CDATA[关上窗吧]]></title>
            <link>https://mylofi.fun/posts/now-close-the-windows/</link>
            <guid isPermaLink="false">https://mylofi.fun/posts/now-close-the-windows/</guid>
            <pubDate>Mon, 12 Aug 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Now Close The Windows - Robert Frost]]></description>
            <content:encoded><![CDATA[<p><em>Now Close the Windows</em><br>
--<em>by Robert Frost(1874-1963)</em></p>
<p><em>Now close the windows and hush all the fields;</em><br>
<em>If the trees must, let them silently toss;</em><br>
<em>No bird is singing now, and if there is,</em><br>
<em>Be it my loss.</em></p>
<p><em>It will be long ere the marshes resume,</em><br>
<em>It will be long ere the earliest bird:</em><br>
<em>So close the windows and not hear the wind,</em><br>
<em>But see all wind-stirred.</em></p>
<blockquote>
<p>👉<a href="https://y.qq.com/n/yqq/album/003atxSh0FYYvY.html">《没有鸟鸣，关上窗吧》by声音碎片</a></p>
</blockquote>]]></content:encoded>
            <category>诗</category>
            <category>摘抄</category>
        </item>
        <item>
            <title><![CDATA[回答]]></title>
            <link>https://mylofi.fun/posts/answer/</link>
            <guid isPermaLink="false">https://mylofi.fun/posts/answer/</guid>
            <pubDate>Mon, 12 Aug 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[一篇名文摘抄：《回答》 --北岛]]></description>
            <content:encoded><![CDATA[<blockquote>
<p>《回答》 -- 北岛</p>
</blockquote>
<p>卑鄙是卑鄙者的通行证，
高尚是高尚者的墓志铭。
看吧，在那镀金的天空中，<br>
飘满了死者弯曲的倒影。</p>
<p>冰川纪过去了，
为什么到处是冰凌？<br>
好望角发现了，<br>
为什么死海里千帆相竞？</p>
<p>我来到这个世界上，
只带着纸、绳索和身影，<br>
为了在审判之前，
宣读那些被判决的声音：</p>
<p>告诉你吧，世界
我 -- 不 -- 相 -- 信！
纵使你脚下有一千名挑战者，
那就把我算做第一千零一名。</p>
<p>我不相信天是蓝的；
我不相信雷的回声；
我不相信梦是假的；
我不相信死无报应。</p>
<p>如果海洋注定要决堤，<br>
就让所有的苦水都注入我心中；
如果陆地注定要上升，
就让人类重新选择生存的封顶。</p>
<p>新的转机和闪闪的星斗，
正在缀满没有遮拦的天空，<br>
那是五千年的象形文字，
那是未来人们凝视的眼睛。</p>]]></content:encoded>
            <category>诗</category>
            <category>摘抄</category>
        </item>
        <item>
            <title><![CDATA[Git 常用命令]]></title>
            <link>https://mylofi.fun/posts/git-command/</link>
            <guid isPermaLink="false">https://mylofi.fun/posts/git-command/</guid>
            <pubDate>Thu, 18 Jul 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[好记性不如烂笔头，记录最常用的几个 git 命令]]></description>
            <content:encoded><![CDATA[<p>新建本地分支并切换到新分支</p>
<pre><code>git checkout -b feat/abc
</code></pre>
<p>本地分支推送到远程（x）</p>
<pre><code>git push origin feat/abc:feat/abc
</code></pre>
<p>设置跟踪（y）</p>
<pre><code>git branch --set-upstream-to=origin/feat/abc feat/abc
</code></pre>
<p>举例：如果想要把新建的 abc 本地分支推送到远程并建立跟踪，需要使用以上 x 和 y 两条命令，也可以使用以下一条命令：</p>
<pre><code>git push -u origin feat/abc
</code></pre>
<p>删除本地分支</p>
<pre><code>git branch -d abc
</code></pre>
<p>如果一个分支还没有被推送或合并，强制删除使用 -D</p>
<pre><code>git branch -D abc
</code></pre>
<p>删除远程分支</p>
<pre><code>git push origin --delete abc
或 
git push origin :abc
</code></pre>]]></content:encoded>
            <category>git</category>
        </item>
        <item>
            <title><![CDATA[车站]]></title>
            <link>https://mylofi.fun/posts/station/</link>
            <guid isPermaLink="false">https://mylofi.fun/posts/station/</guid>
            <pubDate>Mon, 03 Jun 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[一个素不相识的过客]]></description>
            <content:encoded><![CDATA[<blockquote>
<p>一</p>
</blockquote>
<p>这里的地铁很奇怪，不是在地下运行反而是地上，可能是叫「轨道交通」的原因吧。</p>
<p>男孩儿和女孩儿坐在了一起。女孩儿坐姿端正，双目向前，像是在看窗外的风景，风景也不过是些高楼大厦，可能女孩儿是在想些什么吧。男孩儿也端正地坐着，并拿起手机拍了张窗外的照片，男孩儿注意到女孩儿好像微微扭头看了他一眼。随后男孩儿掏出耳机听起了歌，歌名是 stay alive，电影白日梦想家里的插曲。两人就这么坐着，坐着，男孩儿也偷偷把目光放在了女孩儿身上几眼，当然是趁其双目向前的时候。好似两人心有灵犀一般这样博弈了几个回合。男孩儿看着自己两点钟方向的屏幕里播放着某首歌曲的 MV：男主和女主背对背玩石头剪刀布，女主出了布，但是男主却作弊把剪刀换成了石头。这时候男孩儿面带了微笑，女孩儿仿佛也看到了那笑容，空气很安静，安静到报站的声音显得很是洪亮。要下车了。</p>
<blockquote>
<p>二</p>
</blockquote>
<p>男孩儿没有站起来，直到女孩儿起身后。是的，很巧，他们是在同一站下车--火车站。男孩儿似乎窃窃欢喜。两人先后下了地铁，寻找着去向车站候车厅的指示牌，也或者是自助取票机。两人朝着不同的方向走去了，男孩儿转了一圈似乎没有找到正确的入口，站在原地朝着周围的指示标又细细搜寻了一遍，或者是在搜寻那个女孩儿？在那转过身的瞬间，他看到了正面走来的女孩儿，想必是女孩儿也没找到正确的指示标。男孩儿又重复地朝着那个箭头走了过去，这时两个陌生人相向而行。</p>
<blockquote>
<p>三</p>
</blockquote>
<p>男孩儿只是换了个位置原地朝四周打量，女孩儿走了出去，男孩儿若无其事地也随她走了出去。其实哪是若无其事，想必男孩儿内心早已翻江倒海。两人算是并肩，男孩儿看到她摘掉了黑色的帽子，下意识扭头瞄了一眼，并小步向前走去，似是害了臊红了脸想要逃之夭夭。自助取票机终于出现了，就在前面。女孩儿以轻盈的步伐超过了他，此时男孩儿也朝着进站指示牌走了过去。</p>
<blockquote>
<p>四</p>
</blockquote>
<p>男孩儿兜兜转转又走到了几分钟前的原地，没有任何变化。要说有，那就是原地没有那个迎面走来的女孩儿。男孩儿挠了挠头，向旁人问了问路又重新出发了，原来候车亭入口就在自助取票机的另一边，只是男孩儿糊涂走错了方向，把地铁进站指示牌当成了候车厅入口。</p>
<blockquote>
<p>五</p>
</blockquote>
<p>男孩儿排队准备进去候车厅，男孩开始四周张望，却已找不见那个陌生又熟悉的身影，一会儿的功夫，她似丢了。</p>
<blockquote>
<p>六</p>
</blockquote>
<p>男孩儿找到了自己的检票口，离检票还有段时间，他开始在候车厅寻寻觅觅，头戴耳机听着 stay alive。候车厅不是很大，足以让他认真又小心地搜索着匆匆人群好几遍，他一边寻找一边心想，找到她后一定要把这首歌分享给她听。人来人往像流水一样冲过来洗掉一波又一波，他开始害怕自己再也找不到这个女孩儿，于是心生懊悔，怪自己为什么没有勇气趁早和她说上一句话打个招呼，为什么没有勇气挂上一个笑脸看看她，为什么没有把耳机递过去说一句：要不要听。</p>
<blockquote>
<p>七</p>
</blockquote>
<p>这次她丢了。</p>
<blockquote>
<p>八</p>
</blockquote>
<p>男孩儿坐了下来，像是在思考什么，但脑中又一片空白，有的只是耳机里循环的歌曲。</p>
<p>女孩儿穿着长裙，左手带着精致的手表和一个环形的手镯，大概是银色吧，长发过了肩膀，但不是很长，不过此时男孩儿已经忘记了女孩儿的模样。</p>
<blockquote>
<p>九</p>
</blockquote>
<p>车站是一个神奇的地方，它可以给你画上一个圆满的句号，也可以给你一个崭新的起始，但这并不是很重要，重要的是你总会前行，随着每一站的停停留留，都会给你烙下美好、久远的回忆。</p>]]></content:encoded>
            <category>创作</category>
            <category>虚构</category>
        </item>
        <item>
            <title><![CDATA[二零一八，就此作罢]]></title>
            <link>https://mylofi.fun/posts/2018-farewell/</link>
            <guid isPermaLink="false">https://mylofi.fun/posts/2018-farewell/</guid>
            <pubDate>Thu, 03 Jan 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[年终回望：生老病死、辞职、读书、婚礼、摇滚乐，2018 的苦乐交响曲]]></description>
            <content:encoded><![CDATA[<blockquote>
<p>前几天整理邮件发现一个语雀的内测邀请链接，才想起来今年早些时候申请过其内测资格，拿到邀请码后竟把此事给抛在脑后了。恰好，许久没写过什么东西了，第一篇就记录下2018吧。👣</p>
</blockquote>
<h3 id="生死之外无大事"><a href="#生死之外无大事">生死之外无大事</a></h3>
<p>2018这个春节过的并不如意，冷，不仅天气，更寒冷的是家里老人病倒了。年前赶到家时看奶奶第一眼，便眼生泪水，奶奶看到我就一直说个不停，“奶奶老了，不中用了，不会走路了....”，听到这些言语，心里更不是滋味。老爸姑姑长辈们都在一旁坐着，除了说不出的滋味，好像也不知道如何是好。春节过后，我依旧照常南下工作，两周左右，匆匆忙忙赶到家里陪伴老人到最后一刻，那时候意识到自己再也不是那个以前陪奶奶看梨园春频道的小孩子了。真真切切感觉到人世间最悲恸的事，莫过于生老病死，旁人却只能哭泣。</p>
<p>由于那段时间心情处于低谷，工作也不顺心，春节时就有了想换工作的打算。不曾料想在家的时候就收到leader消息说一同事准备离职，对我之后到司的工作做了大概安排，我便也不好说出自己打算离职的想法，一是担心团队人手不够，二是接下来要做一个新项目，所以到司之后就开始做起了项目。项目期间由于时间太紧加班挺严重的，加上当时状态不太好，项目快要做完时就和老大聊了聊，说了自己的想法。老大对我来说亦师亦友，也很感恩老大对我工作的认可，但最后还是提了离职。辞职邮件：
<img src="01.jpeg" alt=""></p>
<p>于我而言，这应该是我做过很酷的一件事了，只想追随自己内心的想法，现在看来也挺感谢当时的年轻气盛，给自己一个机会可以多接触一些不同的人和事。</p>
<h3 id="读书"><a href="#读书">读书</a></h3>
<p>今年大概看了十几本书，有些是在上下班路上看「微信读书」，有些买的纸质。书单：</p>
<ul>
<li>《我是猫》-- 夏目漱石</li>
<li>《影响力》-- 罗伯特·西奥迪尼</li>
<li>《创造自己：一位父亲写给儿子的 116 封信》--刘墉</li>
<li>《第七天》-- 余华</li>
<li>《简约至上：交互式设计四策略》--Giles Golborne</li>
<li>《人工智能》-- 李开复</li>
<li>《在路上》-- 杰克·凯鲁亚克</li>
<li>《房思琪的初恋乐园》--林奕含</li>
<li>《牛奶可乐经济学》-- 罗伯特·弗兰克</li>
<li>《我们仨》-- 杨绛</li>
<li>《解忧杂货店》-- 东野圭吾</li>
<li>《王小波：一只特立独行的猪》-- 王小波</li>
<li>《月亮与六便士》-- 威廉·萨默塞特·毛姆</li>
<li>《一个女人的来信》 -- 茨威格</li>
<li>《苏东坡传》-- 林语堂</li>
<li>《幸福的另一种含义》-- 马克·李维</li>
<li>《与你重逢》-- 马克李维</li>
</ul>
<p>其中给我印象最深刻的一本书--<a href="https://book.douban.com/subject/27614904/">《房思琪的初恋乐园》</a>，这本书是在「微信读书」上看完的，看完之后心情复杂，记下了当时的感受：</p>
<blockquote>
<p>可怕的是人性的深不可测，像黑洞无法揣摩，无法理解，谁又知道黑洞里到底会是什么样子，神秘所以令人生畏。如果有光，必有黑暗是吗？当人看到了月亮，那也一定有看不到的月之暗面。倘若人性有那么的黑暗，丑陋，肮脏，下流，恶心，卑鄙，龌龊，无耻，阴险，自私，令人发指，令人作呕，是不是就会有与之呈绝对相反形态的一面？如果不得不接受这个现实，那好，我相信有黑暗，所以我更相信有光明。有了光，就有了方向，才能指引你到所向往的地方，无论何时，亦无论何处。---2018.07.01</p>
</blockquote>
<p>手头还有几本书没看完，钱老的《围城》和 Jostein Gaarder（乔斯坦·贾徳）的《苏菲的世界》。前段时间又买了两本Patti ·Smith的两本《只是孩子》《时光列车》，还没来得及读，由于自己本身就喜欢音乐，尤其摇滚，所以当初买这两本书也是因为很喜欢Patti的音乐。下边是对Patti简略的介绍，顺便附上2⃣️张超喜欢的图片。</p>
<blockquote>
<p>1975年，她的首张专辑《》受到刚兴起的龐克运动的影响。她将垮掉派诗歌表演和车库乐队摇滚结合在一起，因此被誉为“朋克摇滚桂冠诗人”（Punk's Poet Laureate）和“朋克教母”（Godmother of Punk）。她将19世纪法国作诗法介绍给美国十几岁的年轻人，同时她中性的公众形象和非女性的语言风格挑战着迪斯科时代。2004年，《滚石杂志》颁布的百位摇滚重要人物名单中，将史密斯列为第47位。2007年，她被列入摇滚名人堂。2010年11月17日，她的回忆录《只是孩子》（Just Kids）获得美国国家图书奖。------摘自维基百科。</p>
</blockquote>
<p><img src="02.jpeg" alt=""></p>
<p>很享受看书带来的感觉，就像是自己去体验另一个世界，又能从中汲取营养。突然想起来三字经里有一段写到“苏老泉，二十七，始发愤，读书籍”，这段还是从《苏东坡传》里看到的。讲的是东坡老爹苏洵在二十七岁的时候才开始发愤读书，希望以后还可以坚持读书，笑哈哈。</p>
<h3 id="苦乐交响曲"><a href="#苦乐交响曲">苦乐交响曲</a></h3>
<p>今年5.1是老姐结婚的好日子。喜日前两天忙东忙西把事情搞完，当天凌晨三四点左右起床开始从化妆跟拍，自己也是挺喜欢摄影的，端着相机就充当了跟拍的角色，也没什么经验就当是记录这个特别的日子。婚礼进行时，终于忍不住哭了出来，不知道为什么，就禁不住的一直哭，衣服袖子也被抹湿，好像自己的亲姐就这么成了另外一家人的了一样。生活里总是充满各种感动，不经意间就会让你猝不及防的暴露自己的情感，有时喷薄而出，有时细水长流，希望我们一家人永远都是一家人，无论人在何处。令人遗憾的是奶奶没能参加姐姐的婚礼，相信这也是姐姐最大的遗憾了吧，毕竟姐姐算是被奶奶一手带大的。不过生活也总是充满喜乐和不尽人意，需要的是我们都能以一个端正的态度去对待。</p>
<p>没有人不珍惜自己的生命，但很少人珍惜自己的时间。有时候就觉得很认同「向死而生」的说法，其实人这一生也是这么一个过程，每天都在向死亡靠近，既是生又是死的过程，这种生命倒计时就是向死的过程，生死两点连成一线，怎么个过法还要看自己。原本也是一首苦乐交响曲。</p>
<p><img src="03.png" alt=""></p>
<blockquote>
<p>Bittersweet symphony -- The Verve</p>
<p>Cause it's a bittersweet symphony this life</p>
<p>Trying to make ends meet, you're a slave to the money then you die.</p>
</blockquote>
<h3 id="不要停止我的音乐"><a href="#不要停止我的音乐">不要停止我的音乐</a></h3>
<p>喜欢音乐，喜欢摇滚乐，最喜欢Coldplay。有时候就觉得音乐真是人类最伟大的一项发明了，不管任何时候，任何情况都能听几首歌，沉浸在音符、旋律里，去体会其中的奥妙。音乐来源于生活，来源于平凡的点滴，更能给人带来一种力量，给人鼓舞，让你相信美好的事情。Coldplay于我而言，陪伴了我太多难熬的时刻，我希望他们带给我的这束光永不会灭（Everglow）。曾经感叹过如果还有下辈子，我一定要玩摇滚，享尽孤独和自由。后来发觉，摇滚并不是你不懂专业的乐理知识就不能玩摇滚了，生活不是摇滚吗？是啊！音乐只是一种载体，让我沉浸其中，更是一种态度，是一种向上、自由、愤怒、年轻、不妥协的态度，像鼓点一样铿锵有力，像吉他一样绵延不断，像贝斯一样低沉饱满，像键盘一样热烈美好。</p>
<p><img src="04.jpeg" alt=""></p>
<h3 id="期望"><a href="#期望">期望</a></h3>
<p>对2019没有多大感觉，只是感叹2018时间过的太快。希望自己可以更上层楼，继续听着自己喜欢的歌，多出去走走，背着相机多看看世界认识自己，记录生活。多做饭多吃饭，努力吃胖20斤吧！然后坚持做俯卧撑！希望尽早早的把左臂单手俯卧撑练出来！哈哈哈！😂✊💪</p>
<p>另外，希望自己的英语口语也能有所提高，就这样吧。</p>
<p>繁华盛世，各司其职。</p>]]></content:encoded>
            <category>随笔</category>
        </item>
    </channel>
</rss>