[{"data":1,"prerenderedAt":298},["ShallowReactive",2],{"blog-inp-improvement-case-study":3,"blog-prev-inp-improvement-case-study":97,"blog-next-inp-improvement-case-study":204},{"id":4,"title":5,"author":6,"body":7,"canonical":81,"category":82,"cover":81,"date":83,"description":84,"draft":85,"extension":86,"keywords":81,"meta":87,"navigation":88,"noindex":85,"ogImage":81,"path":89,"seo":90,"seoDescription":81,"seoTitle":81,"stem":91,"tags":92,"updated":81,"__hash__":96},"blog\u002Fblog\u002Finp-improvement-case-study.md","把后台筛选的 INP 从四百二十毫秒压到一百八十","元析智能",{"type":8,"value":9,"toc":70},"minimark",[10,14,17,22,25,28,32,35,39,42,46,49,52,55,58,61,64,67],[11,12,13],"p",{},"今年 10 月我们给一个安全审计 SaaS 的后台做交互优化，P75 的 INP 从 420 毫秒降到 180 毫秒。这个产品每天有客户在里面点几百次筛选，卡不卡直接关系到他们愿不愿意续费。",[11,15,16],{},"问题集中在一个页面：客户列表。1200 条记录，七个筛选条件，每次改动都重新拉数据、重新渲染整张表。用户点一下复选框，页面要停半秒。销售在演示时也遇到过，鼠标点下去没反应，场面很难看。",[18,19,21],"h2",{"id":20},"先复现再动手","先复现，再动手",[11,23,24],{},"我们没有直接改代码，先按真实操作录了 20 次 Performance。结论很清楚：一次筛选交互里，主线程上有三个 300 毫秒以上的长任务，分别是数据深拷贝、全量重渲染、以及一个第三方埋点的同步上报。",[11,26,27],{},"顺带说个细节，客户自己一直说\"不卡\"，因为开发机是 M 系列芯片，而他们的客户用的是四年前的办公本。测 INP 必须用降速环境，或者直接看真实用户数据。",[18,29,31],{"id":30},"改动一列表虚拟化","改动一：列表虚拟化",[11,33,34],{},"1200 行只渲染视口内的 40 行，滚动时动态替换。这一项把重渲染时间从 380 毫秒压到 60 毫秒。虚拟化的代价是导出、全选、跨行拖拽这些功能要单独适配，我们花了三天补。",[18,36,38],{"id":37},"改动二把计算挪出事件处理器","改动二：把计算挪出事件处理器",[11,40,41],{},"原来的筛选逻辑在 onchange 里同步过滤数组、做深拷贝、算统计。改成先更新 UI 状态，计算放到 requestIdleCallback 里分批做，中间留一帧渲染。用户先看到勾选生效，结果稍后到。这个体验上的处理比纯性能数字更重要。",[18,43,45],{"id":44},"改动三埋点改成异步批量","改动三：埋点改成异步批量",[11,47,48],{},"那个第三方埋点在每次筛选时同步上报，一次 80 毫秒。改成 1 秒合并上报，用户交互路径上不再有它。",[18,50,51],{"id":51},"结果和一条教训",[11,53,54],{},"三处改完，P75 从 420 到 180 毫秒，P95 从 1100 到 340 毫秒。客户那边的反馈从\"卡\"变成\"还行\"。",[18,56,57],{"id":57},"落地时的协作问题",[11,59,60],{},"这类改动最大的阻力不是技术，是排期。虚拟化要改列表组件，筛选要改状态管理，埋点要跟第三方沟通，三件事分属三个人的活。我们的做法是先做一行能立刻验证的改动——把埋点延后，半天就上线，第二天客户能自己看到数据变化。有了这个信任，后面两周的排期才好谈。",[11,62,63],{},"另一个坑是回归测试。虚拟化之后导出 CSV、全选、行内编辑全都要重新走一遍。我们让客户的产品经理列了 14 个操作场景，逐个手点，漏一个就是线上事故。",[18,65,66],{"id":66},"一条教训",[11,68,69],{},"不要用开发机测 INP。我们坚持用 CPU 4 倍降速加 4G 网络复现，第一次测出来的数据比客户描述的还差。真实环境总是更差的那个，不会更好。另外 INP 改完不是立刻见效的，我们等了两周真实数据才稳定下来，因为长尾交互要攒够样本。",{"title":71,"searchDepth":72,"depth":72,"links":73},"",2,[74,75,76,77,78,79,80],{"id":20,"depth":72,"text":21},{"id":30,"depth":72,"text":31},{"id":37,"depth":72,"text":38},{"id":44,"depth":72,"text":45},{"id":51,"depth":72,"text":51},{"id":57,"depth":72,"text":57},{"id":66,"depth":72,"text":66},null,"技术SEO","2025-10-16","一个安全审计 SaaS 的客户列表页，1200 条数据七个筛选条件，点一下停半秒。虚拟化、把计算挪出事件处理器、埋点改异步三步做完，P75 从 420 毫秒降到 180 毫秒。",false,"md",{},true,"\u002Fblog\u002Finp-improvement-case-study",{"title":5,"description":84},"blog\u002Finp-improvement-case-study",[93,94,95],"INP","性能复盘","SaaS后台","LLU_4zvtF7huMyfTTrOfWH84dF7njjzyWoG0KX32h-Q",{"id":98,"title":99,"author":6,"body":100,"canonical":81,"category":82,"cover":81,"date":193,"description":194,"draft":85,"extension":86,"keywords":81,"meta":195,"navigation":88,"noindex":85,"ogImage":81,"path":196,"seo":197,"seoDescription":81,"seoTitle":81,"stem":198,"tags":199,"updated":81,"__hash__":203},"blog\u002Fblog\u002Fredirect-chain-cleanup.md","重定向链超过两次，抓取预算就白扔了",{"type":8,"value":101,"toc":185},[102,105,108,129,132,135,138,141,161,164,167,170,173,176,179,182],[11,103,104],{},"重定向链是慢性病。它不报错、不警告，只是每个请求多花一次往返，每个链接多掉一点权重。我们的标准是：超过两跳，当问题处理。",[18,106,107],{"id":107},"链是怎么一年年长出来的",[11,109,110,111,115,116,115,119,115,122,115,125,128],{},"我做诊断时见过最长的一条是六跳：",[112,113,114],"code",{},"http:\u002F\u002Fexample.com\u002Fproduct-a"," → ",[112,117,118],{},"https:\u002F\u002Fexample.com\u002Fproduct-a",[112,120,121],{},"https:\u002F\u002Fwww.example.com\u002Fproduct-a",[112,123,124],{},"\u002Fproducts\u002Fproduct-a",[112,126,127],{},"\u002Fproducts\u002Fproduct-a\u002F"," → 最后才到带版本的落地页。每一跳都对应一次基础设施变更——上 HTTPS 留一层，从裸域切到 www 留一层，改目录再留一层。没人做整体收敛，就这么挂了一年多。",[18,130,131],{"id":131},"六跳改直连的那次",[11,133,134],{},"2025 年 8 月，一个 B2B 软件站的核心产品页就是上面那条链。日志里 Googlebot 对这个页面每天请求 4 次，其中 3 次花在跳转上，真正读到内容只有 1 次。百度蜘蛛更明显，有几天直接停在第二跳就走了。",[11,136,137],{},"改法很简单：在 nginx 层写一条规则，任何旧形态一次 301 到最终 URL，把中间层全删掉。改完第一周，最终页被抓取频次从每天 1 次涨到 4 次，两周后回到前 5。",[18,139,140],{"id":140},"怎么查",[142,143,144,152,158],"ul",{},[145,146,147,148,151],"li",{},"Screaming Frog 跑全站，看 ",[112,149,150],{},"Redirect Chains"," 报表，按跳数排序。",[145,153,154,157],{},[112,155,156],{},"curl -I -L"," 手动盯一个链接，看 Location 头一路跳过几次。",[145,159,160],{},"日志里按状态码 301、302 分组，看哪些路径请求量最大——请求量大的链，修复收益最高。",[18,162,163],{"id":163},"怎么改才不复发",[11,165,166],{},"重定向规则放在 nginx 或 CDN 层，不要写在应用代码里。应用层做重定向，业务一改版就丢规则，而且性能差一截。规则用正则收敛成一条主规则，再给少数特殊路径开白名单。",[11,168,169],{},"302 只给临时活动用，活动结束记得撤。长期挂 302 是最容易被忽略的一种，蜘蛛会一直去请求原地址。有个客户的活动页挂了 14 个月 302，活动早结束了，日志里蜘蛛还在天天抓旧地址，一个月白扔两千多次请求。",[11,171,172],{},"规则写法上，nginx 里优先用一条带正则的 server 级规则做兜底，再给确需保留的路径加 location 例外。CDN 层的回源规则也要同步检查，很多人只改了源站，边缘节点缓存着旧跳转，用户和蜘蛛看到的是两套结果。改完拿三种 UA 各测一次：桌面浏览器、手机浏览器、Googlebot，确认跳转次数一致。",[18,174,175],{"id":175},"多久复查一次",[11,177,178],{},"站点大改、换域名、上 CDN 之后各查一次。平时一个季度扫一遍。重定向链不会自己变好，只会越挂越多。",[18,180,181],{"id":181},"立场",[11,183,184],{},"改版时多花半天做重定向映射，比事后花三个月排查掉排名划算。我们给客户做迁移，301 映射表是必交付物，一张表列清楚旧 URL、新 URL、状态、上线日期，谁接手都能看懂。",{"title":71,"searchDepth":72,"depth":72,"links":186},[187,188,189,190,191,192],{"id":107,"depth":72,"text":107},{"id":131,"depth":72,"text":131},{"id":140,"depth":72,"text":140},{"id":163,"depth":72,"text":163},{"id":175,"depth":72,"text":175},{"id":181,"depth":72,"text":181},"2025-10-15","一个链接从 HTTP 跳 HTTPS、再跳 www、再跳新路径，四次重定向才到目的地。我们清过一条六跳的链，改直连后目标页抓取频次翻了四倍。这篇写链怎么长出来、怎么查、怎么改。",{},"\u002Fblog\u002Fredirect-chain-cleanup",{"title":99,"description":194},"blog\u002Fredirect-chain-cleanup",[200,201,202],"重定向","抓取预算","日志分析","A8hFriWI3vIFk_2oJgg42phX9JCFHPbXnQfPm00PQTk",{"id":205,"title":206,"author":6,"body":207,"canonical":81,"category":285,"cover":81,"date":286,"description":287,"draft":85,"extension":86,"keywords":81,"meta":288,"navigation":88,"noindex":85,"ogImage":81,"path":289,"seo":290,"seoDescription":81,"seoTitle":81,"stem":291,"tags":292,"updated":81,"__hash__":297},"blog\u002Fblog\u002Fpillar-cluster-blog-structure.md","支柱页加簇页，软件站的博客目录该怎么搭",{"type":8,"value":208,"toc":276},[209,212,215,218,221,224,227,230,233,236,239,243,246,249,252,255,258,261,264,267,270,273],[11,210,211],{},"博客目录按时间排是最省事的做法，也是最浪费的做法。我们给一家做安全审计的软件公司重排过 200 多篇文章，分成 6 个问题域，每个域 1 篇支柱页加 10 到 15 篇簇页。12 周后，那 6 篇支柱页里 4 篇进前 20，最好的一篇从第 40 名到第 9 名。",[18,213,214],{"id":214},"支柱页不是目录页",[11,216,217],{},"支柱页是一个问题域的入口，三千字左右，把这个域里的 20 到 30 个子问题都讲一遍，每个子问题给出结论，详细展开交给簇页。",[11,219,220],{},"它得自己是一篇能读的文章，不能只有一堆链接。2025 年 8 月我看过一个客户的“支柱页”，正文 400 字，50 个链接，那不是支柱页，那是导航菜单。",[18,222,223],{"id":223},"一个簇要有几篇才撑得起来",[11,225,226],{},"少于 5 篇簇页，别做支柱页，先老老实实写单篇。",[11,228,229],{},"我们的经验值是 8 到 15 篇。少于 8 篇，支柱页看起来像在硬凑一个主题；超过 15 篇，该拆成两个域了，不然内链会乱。",[18,231,232],{"id":232},"具体怎么搭",[11,234,235],{},"以“单点登录”这个域为例。支柱页叫“单点登录的 12 个工程问题”，簇页是“SSO 和 OAuth 的区别”“SAML 断言签名失败怎么排查”“多租户系统怎么做 SSO”这类，每篇两千字上下。",[11,237,238],{},"每篇簇页开头一句链回支柱页，结尾再链两个同域的其他簇页。支柱页正文里，每个子问题后面挂一个“展开看”的链接。",[18,240,242],{"id":241},"url-和目录结构","URL 和目录结构",[11,244,245],{},"我们建议用 \u002Fblog\u002Fsso\u002F 这样的路径放整个簇，而不是把 200 篇全塞在 \u002Fblog\u002F 下。路径带主题，内链和统计都好管。",[11,247,248],{},"改动 URL 要 301，并且一次只动一个簇。我们有过一次动全站路径的教训，恢复收录花了六周。",[18,250,251],{"id":251},"常见错误",[11,253,254],{},"支柱页写成纯目录；簇页之间完全不互链；一个主题硬塞进 30 篇，读者找不到重点；还有就是支柱页更新了，簇页还是两年前的内容，整组一起过期。",[18,256,257],{"id":257},"支柱页的更新节奏",[11,259,260],{},"支柱页每半年更新一次，主要是补新出现的子问题和换数据。更新时标题和 URL 都不动，只改正文和日期。",[11,262,263],{},"簇页写完之后如果发现支柱页缺这个子问题，先补支柱页，再发簇页。顺序反了，新簇页会变成孤儿页，只能靠内链慢慢被发现。",[18,265,266],{"id":266},"簇页之间怎么不写重复",[11,268,269],{},"每个簇页只回答一个问题，标题里只出现一个核心词。写之前把同簇的 10 个标题摆在一起看，如果两个标题能让读者分不清该点哪个，就合并。",[11,271,272],{},"我们在一个 12 篇的簇里干过这事，选题时看着都不同，写完发现 3 篇在讲同一件事，最后并成 1 篇加 301。",[11,274,275],{},"我们判断一个站的博客能不能起量，先看它有没有 3 个完整的簇。有 3 个，说明内容是真按问题域排的；只有一堆散篇，写再多也只是在填目录。",{"title":71,"searchDepth":72,"depth":72,"links":277},[278,279,280,281,282,283,284],{"id":214,"depth":72,"text":214},{"id":223,"depth":72,"text":223},{"id":232,"depth":72,"text":232},{"id":241,"depth":72,"text":242},{"id":251,"depth":72,"text":251},{"id":257,"depth":72,"text":257},{"id":266,"depth":72,"text":266},"内容运营","2025-10-17","博客目录不该按发布时间排，该按问题域排。我们给一家安全软件公司把 200 篇文章重组成 6 个簇，支柱页从第 40 名爬到第 9 名，簇页平均曝光涨了 2.3 倍。",{},"\u002Fblog\u002Fpillar-cluster-blog-structure",{"title":206,"description":287},"blog\u002Fpillar-cluster-blog-structure",[293,294,295,296],"内容架构","支柱页","主题簇","内链","mcRmw5GL8i4qV3fZd2Ux5rGkweO7dmreOveWmT5HQhs",1794088111589]