<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Efficacy on 技術、遊戲、生活通俗易懂的解釋</title><link>https://takao.blog/zh-tw/tags/efficacy/</link><description>Recent content in Efficacy on 技術、遊戲、生活通俗易懂的解釋</description><generator>Hugo -- gohugo.io</generator><language>zh-tw</language><copyright>Commentary of Takao</copyright><lastBuildDate>Wed, 08 Jul 2026 10:00:00 +0900</lastBuildDate><atom:link href="https://takao.blog/zh-tw/tags/efficacy/index.xml" rel="self" type="application/rss+xml"/><item><title>Web Performance Monitoring 工具 Compared 2026</title><link>https://takao.blog/zh-tw/web/web-performance-monitoring-tools-2026/</link><pubDate>Wed, 08 Jul 2026 10:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/web-performance-monitoring-tools-2026/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/web-performance-monitoring-tools-2026-zh-tw.png" alt="Featured image of post Web Performance Monitoring 工具 Compared 2026" /&gt;&lt;h2 id="why-lighthouse-is-not-enough"&gt;Why Lighthouse Is Not Enough
&lt;/h2&gt;&lt;p&gt;Lighthouse is an excellent diagnostic tool, but it only measures lab data, not real user experience. Standard practice in 2026 combines lab measurements with Real User Monitoring (RUM).&lt;/p&gt;
&lt;h2 id="1-web-vitals--chrome-ux-report-and-crux-api"&gt;1. Web Vitals — Chrome UX Report and CrUX API
&lt;/h2&gt;&lt;p&gt;Google&amp;rsquo;s Chrome UX Report aggregates field data from real Chrome users. You can query it via API to analyze both your own and competitors&amp;rsquo; sites.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;response&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;await&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;fetch&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;https://chromeuxreport.googleapis.com/v1/records:queryRecord?key=YOUR_KEY&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;method&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;body&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;JSON&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;stringify&lt;/span&gt;({
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;origin&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;https://example.com&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;metrics&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; [&lt;span style="color:#e6db74"&gt;&amp;#39;largest_contentful_paint&amp;#39;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#39;cumulative_layout_shift&amp;#39;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="2-sentry-performance"&gt;2. Sentry Performance
&lt;/h2&gt;&lt;p&gt;Well-known for error monitoring, Sentry also offers robust performance tracing. It captures transactions end-to-end, from frontend to backend, with automatic instrumentation for React and Next.js. Setup takes minutes.&lt;/p&gt;</description></item><item><title>Isolating Layout Computations via CSS contain 正確的ty</title><link>https://takao.blog/zh-tw/web/performance-css-contain-property/</link><pubDate>Mon, 15 Jun 2026 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/performance-css-contain-property/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/performance-css-contain-property-zh-tw.png" alt="Featured image of post Isolating Layout Computations via CSS contain 正確的ty" /&gt;&lt;h2 id="the-rendering-cost-of-dynamic-content"&gt;The Rendering Cost of Dynamic Content
&lt;/h2&gt;&lt;p&gt;Every time the DOM changes, the browser must recompute styles, layout, and paint. For pages with many interactive widgets—chat feeds, stock tickers, infinite-scroll lists—these recalculations can ripple across the entire document, causing jank and dropped frames.&lt;/p&gt;
&lt;p&gt;The CSS &lt;code&gt;contain&lt;/code&gt; property tells the browser that a subtree is &lt;strong&gt;independent&lt;/strong&gt; from the rest of the page. This enables the engine to skip global recalculations and treat the element as an isolated island.&lt;/p&gt;</description></item><item><title>使用 DNS 預取和預連線加速資產加載</title><link>https://takao.blog/zh-tw/web/performance-dns-prefetch-preconnect/</link><pubDate>Wed, 15 Apr 2026 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/performance-dns-prefetch-preconnect/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/performance-dns-prefetch-preconnect-zh-tw.png" alt="Featured image of post 使用 DNS 預取和預連線加速資產加載" /&gt;&lt;h2 id="介紹"&gt;介紹
&lt;/h2&gt;&lt;p&gt;每個外部資源（字體、腳本、映像、API 端點）都需要網路連線。 &lt;strong&gt;DNS 解析&lt;/strong&gt;、&lt;strong&gt;TCP 握手&lt;/strong&gt;和 &lt;strong&gt;TLS 協商&lt;/strong&gt;的開銷可能會導致頁面載入時間增加數百毫秒。 &lt;strong&gt;資源提示&lt;/strong&gt;如 &lt;code&gt;dns-prefetch&lt;/code&gt; 和 &lt;code&gt;preconnect&lt;/code&gt; 讓您告訴瀏覽器在實際需要資源之前&lt;strong&gt;提前&lt;/strong&gt;執行這些步驟。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="連接成本"&gt;連接成本
&lt;/h2&gt;&lt;p&gt;建立 HTTPS 連線涉及多次往返：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;步驟&lt;/th&gt;
					&lt;th&gt;延遲（大約）&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;DNS 查找&lt;/td&gt;
					&lt;td&gt;20-120 毫秒&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;TCP握手&lt;/td&gt;
					&lt;td&gt;1 個RTT&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;TLS 協商&lt;/td&gt;
					&lt;td&gt;2 即時傳輸時間&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;總計&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;3+ RTT&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;在 3G 連線（300 毫秒 RTT）上，傳輸任何資料之前需要近 &lt;strong&gt;1 秒&lt;/strong&gt;的開銷。資源提示消除了大部分內容。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="dns-預取"&gt;DNS 預取
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;dns-prefetch&lt;/code&gt; &lt;strong&gt;提前解析網域&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;dns-prefetch&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;https://fonts.googleapis.com&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;這會在瀏覽器仍在解析 HTML 的同時啟動網域的 DNS 查找。當瀏覽器遇到來自該來源的資源時，IP 位址已被快取。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;何時使用：&lt;/strong&gt; 簡單地引用外部網域。它是輕量級的－只有 DNS 解析，沒有開啟連線。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="預連接"&gt;預連接
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;preconnect&lt;/code&gt; 更進一步：它執行 &lt;strong&gt;DNS 查找 + TCP 握手 + TLS 協商&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;link&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;rel&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;preconnect&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;href&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;https://api.example.com&amp;#34;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;crossorigin&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;使用 CORS 模式載入的資源（字體、取得請求等）需要 &lt;code&gt;crossorigin&lt;/code&gt; 屬性。&lt;/p&gt;</description></item><item><title>Optimizing Web Font Loading: 預防ing FOUT and FOIT</title><link>https://takao.blog/zh-tw/web/performance-fonts-loading-optimization/</link><pubDate>Sun, 15 Mar 2026 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/performance-fonts-loading-optimization/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/performance-fonts-loading-optimization-zh-tw.png" alt="Featured image of post Optimizing Web Font Loading: 預防ing FOUT and FOIT" /&gt;&lt;h2 id="introduction"&gt;Introduction
&lt;/h2&gt;&lt;p&gt;Web fonts enhance design but come at a cost. While a custom font loads, browsers must decide: show invisible text (&lt;strong&gt;FOIT&lt;/strong&gt; — Flash of Invisible Text) or show a fallback font (&lt;strong&gt;FOUT&lt;/strong&gt; — Flash of Unstyled Text). Either choice impacts &lt;strong&gt;CLS (Cumulative Layout Shift)&lt;/strong&gt; and user experience. This article covers strategies to load fonts reliably while minimizing layout shifts.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-font-display-descriptor"&gt;The font-display Descriptor
&lt;/h2&gt;&lt;p&gt;The &lt;code&gt;font-display&lt;/code&gt; property in &lt;code&gt;@font-face&lt;/code&gt; controls how a font is displayed during loading:&lt;/p&gt;</description></item><item><title>React 編譯器：告別手動記憶</title><link>https://takao.blog/zh-tw/web/react-compiler-automated-memoization/</link><pubDate>Sat, 10 Jan 2026 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/react-compiler-automated-memoization/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/react-compiler-automated-memoization-zh-tw.png" alt="Featured image of post React 編譯器：告別手動記憶" /&gt;&lt;h2 id="介紹"&gt;介紹
&lt;/h2&gt;&lt;p&gt;多年來，React 開發人員一直使用 &lt;code&gt;useMemo&lt;/code&gt;、&lt;code&gt;useCallback&lt;/code&gt;、&lt;code&gt;React.memo&lt;/code&gt; 和各種狀態管理啟發式方法手動優化重新渲染。 &lt;strong&gt;React Compiler&lt;/strong&gt;（以前稱為 React Forget）完全改變了這個範例。它是一個建置時工具，透過在編譯時分析反應依賴關係來自動記憶 React 元件、鉤子和值，從而無需手動最佳化鉤子。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="手動記憶的問題"&gt;手動記憶的問題
&lt;/h2&gt;&lt;p&gt;考慮一個典型的過濾列表元件：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UserList&lt;/span&gt;({ &lt;span style="color:#a6e22e"&gt;users&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;filter&lt;/span&gt; }) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;filtered&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;useMemo&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; () =&amp;gt; &lt;span style="color:#a6e22e"&gt;users&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;filter&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;u&lt;/span&gt; =&amp;gt; &lt;span style="color:#a6e22e"&gt;u&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;includes&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;filter&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#a6e22e"&gt;users&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;filter&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handleClick&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;useCallback&lt;/span&gt;((&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;console&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#39;Clicked:&amp;#39;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, []);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;ul&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;filtered&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;map&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;user&lt;/span&gt; =&amp;gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;UserRow&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;key&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;user&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;} &lt;span style="color:#a6e22e"&gt;user&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;user&lt;/span&gt;} &lt;span style="color:#a6e22e"&gt;onClick&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;handleClick&lt;/span&gt;} /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ))}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;/&lt;span style="color:#f92672"&gt;ul&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;UserRow&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;React&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;memo&lt;/span&gt;(({ &lt;span style="color:#a6e22e"&gt;user&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;onClick&lt;/span&gt; }) =&amp;gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;li&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;onClick&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{() =&amp;gt; &lt;span style="color:#a6e22e"&gt;onClick&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;user&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;id&lt;/span&gt;)}&amp;gt;{&lt;span style="color:#a6e22e"&gt;user&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;}&amp;lt;/&lt;span style="color:#f92672"&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;這是可行的，但它很冗長，容易出錯（依賴項數組遺失或不正確），並且很容易忘記。大列表中缺少 &lt;code&gt;useMemo&lt;/code&gt; 會導致不必要的重新渲染；不正確的依賴數組會導致陳舊的閉包。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="什麼是-react-編譯器"&gt;什麼是 React 編譯器？
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;React Compiler&lt;/strong&gt; 是一個建置時插件（Babel / SWC），可以自動理解 React 元件的反應性模型。它會自動轉譯您的程式碼以包含記憶邏輯：&lt;/p&gt;</description></item><item><title>優化瀏覽器渲染管道（關鍵路徑）</title><link>https://takao.blog/zh-tw/web/performance-critical-rendering-path-optimizations/</link><pubDate>Sat, 20 Dec 2025 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/performance-critical-rendering-path-optimizations/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/performance-critical-rendering-path-optimizations-zh-tw.png" alt="Featured image of post 優化瀏覽器渲染管道（關鍵路徑）" /&gt;&lt;h2 id="介紹"&gt;介紹
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;關鍵渲染路徑 (CRP)&lt;/strong&gt; 是瀏覽器執行的將 HTML、CSS 和 JavaScript 轉換為螢幕上可見像素的步驟序列。優化此管道直接影響&lt;strong&gt;第一內容繪製 (FCP)&lt;/strong&gt; 和 &lt;strong&gt;最大內容繪製 (LCP)&lt;/strong&gt;。本文詳細介紹了每個 CRP 階段——DOM 構建、CSSOM 構建、渲染樹、佈局、繪製和合成——並提供了可行的最佳化策略。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="第一階段dom-構建"&gt;第一階段：DOM 構建
&lt;/h2&gt;&lt;p&gt;當瀏覽器接收到 HTML 位元組時，它：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;位元組→字元&lt;/strong&gt;：將原始位元組解碼為字符&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;標記化&lt;/strong&gt;：將字元轉換為標記（&lt;code&gt;StartTag&lt;/code&gt;、&lt;code&gt;EndTag&lt;/code&gt; 等）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lexing&lt;/strong&gt;：將令牌轉換為節點&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DOM Tree&lt;/strong&gt;：建立保留父子關係的節點樹&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;!-- This HTML produces a DOM tree with html &amp;gt; head + body &amp;gt; h1 + p --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;html&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;head&lt;/span&gt;&amp;gt;&amp;lt;&lt;span style="color:#f92672"&gt;title&lt;/span&gt;&amp;gt;Page&amp;lt;/&lt;span style="color:#f92672"&gt;title&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style="color:#f92672"&gt;head&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;h1&lt;/span&gt;&amp;gt;Hello&amp;lt;/&lt;span style="color:#f92672"&gt;h1&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;World&amp;lt;/&lt;span style="color:#f92672"&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;body&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;/&lt;span style="color:#f92672"&gt;html&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;最佳化&lt;/strong&gt;：最小化 HTML 大小，透過正確的伺服器配置儘早交付，並使用 &lt;strong&gt;串流&lt;/strong&gt;（例如 &lt;code&gt;Transfer-Encoding: chunked&lt;/code&gt;）。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="第-2-階段cssom-構建"&gt;第 2 階段：CSSOM 構建
&lt;/h2&gt;&lt;p&gt;預設情況下，CSS 是&lt;strong&gt;渲染阻塞&lt;/strong&gt;的。瀏覽器在渲染之前必須下載並解析所有CSS。 CSS 位元組與 HTML 經歷相同的轉換管道，產生 &lt;strong&gt;CSS 物件模型 (CSSOM)&lt;/strong&gt;。&lt;/p&gt;</description></item><item><title>預防ing Cumulative Layout Shift with CSS aspect-ratio</title><link>https://takao.blog/zh-tw/web/css-aspect-ratio-cumulative-layout-shift/</link><pubDate>Wed, 10 Dec 2025 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/css-aspect-ratio-cumulative-layout-shift/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/css-aspect-ratio-cumulative-layout-shift-zh-tw.png" alt="Featured image of post 預防ing Cumulative Layout Shift with CSS aspect-ratio" /&gt;&lt;h2 id="understanding-cumulative-layout-shift"&gt;Understanding Cumulative Layout Shift
&lt;/h2&gt;&lt;p&gt;Cumulative Layout Shift (CLS) is one of Google&amp;rsquo;s &lt;strong&gt;Core Web Vitals&lt;/strong&gt; metrics that measures visual stability. It quantifies how often users experience unexpected layout shifts. A high CLS score harms user experience and SEO rankings. The primary cause? Media elements (images, videos, iframes) loading without reserved space.&lt;/p&gt;
&lt;h2 id="how-css-aspect-ratio-works"&gt;How CSS aspect-ratio Works
&lt;/h2&gt;&lt;p&gt;The &lt;code&gt;aspect-ratio&lt;/code&gt; CSS property lets you declare the ratio of width to height for any element. The browser reserves space accordingly, preventing the layout from jumping when content loads.&lt;/p&gt;</description></item><item><title>最大化 Docker Build Cache for Faster Deployment Pipelines</title><link>https://takao.blog/zh-tw/web/docker-build-caches-speedup/</link><pubDate>Sat, 20 Sep 2025 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/docker-build-caches-speedup/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/docker-build-caches-speedup-zh-tw.png" alt="Featured image of post 最大化 Docker Build Cache for Faster Deployment Pipelines" /&gt;&lt;p&gt;Whether you are trying to speed up 本地 iterative container runs or aiming to shave minutes off your CI/CD pipelines, optimizing your &lt;strong&gt;Docker image build speeds&lt;/strong&gt; is a crucial aspect of engineering productivity. Long build wait times disrupt developer focus and drive up cloud computing costs.&lt;/p&gt;
&lt;p&gt;One of the most powerful and easiest ways to optimize build speeds is by configuring Docker files to maximize the use of the &lt;strong&gt;Docker Build Cache&lt;/strong&gt;.&lt;/p&gt;</description></item><item><title>使用 requestIdleCallback 執行非阻塞腳本</title><link>https://takao.blog/zh-tw/web/web-performance-requestidlecallback-optimizations/</link><pubDate>Fri, 25 Jul 2025 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/web-performance-requestidlecallback-optimizations/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/web-performance-requestidlecallback-optimizations-zh-tw.png" alt="Featured image of post 使用 requestIdleCallback 執行非阻塞腳本" /&gt;&lt;h2 id="介紹"&gt;介紹
&lt;/h2&gt;&lt;p&gt;在建立複雜的 Web 應用程式時，保持流暢的動畫和響應式使用者輸入（理想情況下匹配 60+ FPS 幀速率）對於良好的使用者體驗至關重要。&lt;/p&gt;
&lt;p&gt;然而，現代應用程式通常需要執行低優先順序的後台操作，例如發送分析資料、同步快取、解析遙測日誌或預取資產。&lt;/p&gt;
&lt;p&gt;作為標準非同步承諾或立即計時器執行這些非緊急任務可能會阻塞主線程中幀，導致介面卡頓或增加下次繪製交互 (INP) 分數。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;requestIdleCallback&lt;/code&gt;&lt;/strong&gt; API 解決了這個問題。本文回顧了 API 的工作原理並分享了生產程式碼庫的實際用例。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="1什麼是requestidlecallback"&gt;1.什麼是requestIdleCallback？
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;requestIdleCallback&lt;/code&gt; 是一個本機瀏覽器 API，允許您&lt;strong&gt;對低優先權後台任務進行排隊，以便在瀏覽器空閒期間&lt;/strong&gt;（主執行緒完成渲染更新並等待使用者輸入時的間隙）運行。&lt;/p&gt;
&lt;h3 id="瀏覽器渲染週期"&gt;瀏覽器渲染週期
&lt;/h3&gt;&lt;p&gt;通常，瀏覽器會嘗試在單一畫面（大約 16.6 毫秒）內執行下列步驟：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[Single Frame (approx 16.6ms)]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ├─► 1. Process user inputs (clicks, keypresses)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ├─► 2. Execute active macro-tasks (setTimeout/setInterval)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ├─► 3. Run requestAnimationFrame updates
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ├─► 4. Recalculate layout &amp;amp; paint pixels
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; └─► 5. 【Browser Idle Period】 ◄── requestIdleCallback runs here!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果瀏覽器提前完成渲染更新，它將使用剩餘時間來執行 &lt;code&gt;requestIdleCallback&lt;/code&gt; 中排隊的任務。如果發生高優先權事件（例如按一下或觸控輸入），瀏覽器會立即將控制權交還給主渲染循環，以保持 UI 回應。&lt;/p&gt;</description></item><item><title>提升ing Initial Page Speeds with Lazy-Loaded Frames and Images</title><link>https://takao.blog/zh-tw/web/web-performance-lazyloading-iframe/</link><pubDate>Sun, 20 Jul 2025 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/web-performance-lazyloading-iframe/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/web-performance-lazyloading-iframe-zh-tw.png" alt="Featured image of post 提升ing Initial Page Speeds with Lazy-Loaded Frames and Images" /&gt;&lt;h2 id="introduction"&gt;Introduction
&lt;/h2&gt;&lt;p&gt;An effective but frequently overlooked strategy for optimizing web page speeds is &lt;strong&gt;deferring off-screen asset loading&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;By default, when a user loads a web page, the browser immediately requests all images and &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; elements (like YouTube embeds, interactive maps, social widgets, or advertising scripts) on the page, even if they are located far below the fold. This concurrent downloading blocks the main thread and slows down your page&amp;rsquo;s First Contentful Paint (FCP) time.&lt;/p&gt;</description></item><item><title>優化影像：WebP 與 AVIF 以及響應式尺寸</title><link>https://takao.blog/zh-tw/web/web-performance-image-optimizations/</link><pubDate>Tue, 15 Jul 2025 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/web-performance-image-optimizations/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/web-performance-image-optimizations-zh-tw.png" alt="Featured image of post 優化影像：WebP 與 AVIF 以及響應式尺寸" /&gt;&lt;h2 id="介紹"&gt;介紹
&lt;/h2&gt;&lt;p&gt;優化影像資源是提高 Lighthouse 分數和 LCP（最大內容繪製）等 Web 效能指標最有效的方法之一。&lt;/p&gt;
&lt;p&gt;在許多 Web 應用程式中，圖像佔總負載大小的一半以上。緩慢的圖像載入時間直接降低了用戶體驗。&lt;/p&gt;
&lt;p&gt;以 &lt;strong&gt;WebP&lt;/strong&gt; 和 &lt;strong&gt;AVIF&lt;/strong&gt; 等下一代格式取代 JPEG 和 PNG 等傳統格式已成為現代 Web 開發的標準做法。本文比較了這兩種格式，並解釋如何配置響應式、最佳化的影像傳輸。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="1-比較下一代格式webp-與-avif"&gt;1. 比較下一代格式：WebP 與 AVIF
&lt;/h2&gt;&lt;p&gt;與 JPEG 和 PNG 相比，下一代格式可以更有效地壓縮文件，同時保持視覺品質。&lt;/p&gt;
&lt;h3 id="-網頁版"&gt;① 網頁版
&lt;/h3&gt;&lt;p&gt;WebP 由 Google 開發，是一種多功能圖像格式。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;特點：&lt;/strong&gt; 同時支援有損壓縮（替代JPEG）和無損壓縮（替代PNG）。它還支援 Alpha 通道透明度和動畫。&lt;/li&gt;
&lt;li&gt;**壓縮：**與同等質量的 JPEG 相比，檔案大小減少 &lt;strong&gt;25% 到 30%&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;支援：&lt;/strong&gt; 幾乎所有現代網頁瀏覽器都支援，使其成為網頁圖像的事實上的標準。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="-avif"&gt;② AVIF
&lt;/h3&gt;&lt;p&gt;AVIF 是一種基於 AV1 視訊編解碼器的開放、免版稅的影像格式。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;特點：&lt;/strong&gt; 提供比 WebP 更高的壓縮比，並支援廣色域和 HDR。它在處理漸變和詳細的攝影影像時表現良好，最大限度地減少了壓縮偽影。&lt;/li&gt;
&lt;li&gt;**壓縮：**與同等 JPEG 相比，檔案大小減少 &lt;strong&gt;50% 或更多&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;支援：&lt;/strong&gt; Chrome、Firefox 和 Safari 等主流瀏覽器的支持，使其為生產環境做好準備。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="2-使用-html--元素進行後備交付"&gt;2. 使用 HTML &lt;!-- raw HTML omitted --&gt; 元素進行後備交付
&lt;/h2&gt;&lt;p&gt;由於並非所有瀏覽器都支援 AVIF，因此建議的方法是提供後備鏈：如果支持，則提供 AVIF，秋季返回 WebP，並使用標準 JPEG 或 PNG 作為最終後備。&lt;/p&gt;</description></item><item><title>停止在 React 中過度使用 useMemo 和 useCallback</title><link>https://takao.blog/zh-tw/web/react-hooks-usememo-usecallback/</link><pubDate>Fri, 20 Jun 2025 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/react-hooks-usememo-usecallback/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/react-hooks-usememo-usecallback-zh-tw.png" alt="Featured image of post 停止在 React 中過度使用 useMemo 和 useCallback" /&gt;&lt;h2 id="介紹"&gt;介紹
&lt;/h2&gt;&lt;p&gt;在最佳化 React 應用程式效能時，開發人員通常會使用 &lt;strong&gt;&lt;code&gt;useMemo&lt;/code&gt;&lt;/strong&gt; 和 &lt;strong&gt;&lt;code&gt;useCallback&lt;/code&gt;&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;人们很容易将每个对象和函数包装在这些钩子中，假设缓存输出将自动加速应用程序。然而，這是一個常見的誤解。&lt;/p&gt;
&lt;p&gt;不必要的記憶不僅會使程式碼更難閱讀，而且還會使程式碼更難閱讀。它增加了&lt;strong&gt;淺依賴項比較和垃圾收集記憶體分配的效能開銷&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;本文概述了這些鉤子有益的具體場景以及何時應避免它們。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="1-記憶的隱性成本"&gt;1. 記憶的隱性成本
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;useMemo&lt;/code&gt; 和 &lt;code&gt;useCallback&lt;/code&gt; 都不是自由操作。它們在每個渲染週期都會產生運行時成本：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;依賴關係比較開銷：&lt;/strong&gt;
在每次渲染時，React 必須淺比較（使用 &lt;code&gt;Object.is&lt;/code&gt;）依賴項數組中的每個值。執行這些陣列檢查會增加 CPU 開銷。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;記憶體保留：&lt;/strong&gt;
保留對先前函數或計算值的參考可以防止它們被垃圾收集，從而增加應用程式的記憶體佔用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;複雜性與錯誤：&lt;/strong&gt;
錯誤配置的依賴數組可能會導致陳舊的閉包，其中函數引用過時的狀態或道具。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="2-usememo-使用指南"&gt;2. useMemo 使用指南
&lt;/h2&gt;&lt;p&gt;僅在以下兩種情況下使用 &lt;code&gt;useMemo&lt;/code&gt;：&lt;/p&gt;
&lt;h3 id="場景-a計算量大的任務"&gt;場景 A：計算量大的任務
&lt;/h3&gt;&lt;p&gt;將其用於 CPU 密集型操作，例如對大型數組進行排序、過濾複雜資料集或運行繁重的映射操作。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;推薦用例：&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Memoize search calculations on large lists
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;filteredItems&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;useMemo&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;heavySearch&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;items&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;query&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }, [&lt;span style="color:#a6e22e"&gt;items&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;query&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="場景-b保留-reactmemo-的物件引用"&gt;場景 B：保留 React.memo 的物件引用
&lt;/h3&gt;&lt;p&gt;React 在每次渲染時重新實例化元件內部的物件聲明，更改它們的記憶體位址。&lt;/p&gt;
&lt;p&gt;如果一個物件作為 prop 傳遞給使用 &lt;code&gt;React.memo&lt;/code&gt; 最佳化的子元件，則子元件無論如何都會重新渲染，因為物件參考發生了變化。使用 &lt;code&gt;useMemo&lt;/code&gt; 保持引用穩定。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;推薦用例：&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-jsx" data-lang="jsx"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Stabilize the options object reference
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;options&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;useMemo&lt;/span&gt;(() =&amp;gt; ({ &lt;span style="color:#a6e22e"&gt;color&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;themeColor&lt;/span&gt; }), [&lt;span style="color:#a6e22e"&gt;themeColor&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Sibling components optimized with React.memo will not re-render unnecessarily
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &amp;lt;&lt;span style="color:#f92672"&gt;HeavyChildComponent&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;options&lt;/span&gt;} /&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="3-usecallback使用指南"&gt;3. useCallback使用指南
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;useCallback&lt;/code&gt; 的目的不是防止函數重新實例化，而是&lt;strong&gt;跨渲染保留函數的記憶體參考&lt;/strong&gt;。&lt;/p&gt;</description></item><item><title>資料庫索引簡介：解決查詢延遲</title><link>https://takao.blog/zh-tw/web/backend-database-indexing-basics/</link><pubDate>Sun, 25 May 2025 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/backend-database-indexing-basics/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/backend-database-indexing-basics-zh-tw.png" alt="Featured image of post 資料庫索引簡介：解決查詢延遲" /&gt;&lt;h2 id="介紹"&gt;介紹
&lt;/h2&gt;&lt;p&gt;隨著 Web 應用程式的擴展和資料量的成長，後端系統經常面臨查詢延遲等資料庫瓶頸問題。&lt;/p&gt;
&lt;p&gt;在沒有適當索引優化的情況下，在具有數十萬筆記錄的表上執行聯接 (&lt;code&gt;JOIN&lt;/code&gt;) 操作或複雜的搜尋查詢可能會導致資料庫 CPU 峰值，從而導致最終用戶的回應時間變慢。&lt;/p&gt;
&lt;p&gt;設計資料庫索引是解決這些效能瓶頸的有效方法。本文解釋了資料庫索引的工作原理，詳細介紹了 B 樹結構，並分享了設計有效索引的指南。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="1-為什麼索引可以加快查詢速度"&gt;1. 為什麼索引可以加快查詢速度？
&lt;/h2&gt;&lt;p&gt;將資料庫索引視為教科書後面的索引部分。&lt;/p&gt;
&lt;p&gt;如果沒有索引，搜尋特定主題需要您掃描從開始到餘韻的每一頁。在資料庫中，這稱為&lt;strong&gt;全表掃描（All Table Scan）&lt;/strong&gt;。隨著資料量的增加，這種線性掃描過程需要更長的時間。&lt;/p&gt;
&lt;p&gt;透過在特定列上建立索引，資料庫以排序結構組織資料並記錄對實體行的參考（指標）。這使得查詢引擎可以快速找到目標記錄。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="2-b-樹索引的機制"&gt;2. B 樹索引的機制
&lt;/h2&gt;&lt;p&gt;關聯式資料庫（如 MySQL 和 PostgreSQL）通常使用&lt;strong&gt;B-Tree（平衡樹）索引&lt;/strong&gt;結構。&lt;/p&gt;
&lt;p&gt;B 樹將鍵組織成由根節點、中間節點和葉節點組成的平衡樹佈局。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [Root Node]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; / \
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [100] [200]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; / \ / \
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [...] [...] [...] [Leaf Nodes] -&amp;gt; References to physical rows
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="如何執行搜尋"&gt;如何執行搜尋
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;搜尋查詢從頂級根節點開始。&lt;/li&gt;
&lt;li&gt;查詢引擎將目標鍵值與節點值進行比較，以確定要遵循哪個子分支指標。&lt;/li&gt;
&lt;li&gt;這個過程向下重複到葉節點，葉節點包含指向磁碟上實體行的指標（如 ROWID），允許引擎取得匹配的記錄。&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;好處：&lt;/strong&gt; 無論表格成長多大，搜尋複雜度都會以 &lt;code&gt;O(log N)&lt;/code&gt; 對數縮放。這使得查找時間變快，通常在幾毫秒內解析。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="3-設計資料庫索引的三個準則"&gt;3. 設計資料庫索引的三個準則
&lt;/h2&gt;&lt;p&gt;雖然索引可以提高搜尋速度，但在每一列上建立索引會適得其反。每個寫入作業（&lt;code&gt;INSERT&lt;/code&gt;、&lt;code&gt;UPDATE&lt;/code&gt;、&lt;code&gt;DELETE&lt;/code&gt;）都需要更新對應的索引結構，這會增加開銷，從而降低寫入效能。&lt;/p&gt;
&lt;p&gt;使用這三個準則來決定何時建立索引：&lt;/p&gt;
&lt;h3 id="準則-1具有高基數的目標列選擇性"&gt;準則 1：具有高基數的目標列（選擇性）
&lt;/h3&gt;&lt;p&gt;基數是指儲存在列中的&lt;strong&gt;唯一值的數量&lt;/strong&gt;。&lt;/p&gt;</description></item><item><title>Approaches to Improving Interaction to Next 疼痛t (INP)</title><link>https://takao.blog/zh-tw/web/performance-web-vitals-inp/</link><pubDate>Sat, 15 Mar 2025 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/performance-web-vitals-inp/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/performance-web-vitals-inp-zh-tw.png" alt="Featured image of post Approaches to Improving Interaction to Next 疼痛t (INP)" /&gt;&lt;h2 id="introduction"&gt;Introduction
&lt;/h2&gt;&lt;p&gt;In Google&amp;rsquo;s &lt;strong&gt;Core Web Vitals&lt;/strong&gt; metrics, which measure the user experience of web pages, FID (First Input Delay) has officially been replaced by &lt;strong&gt;INP (Interaction to Next Paint)&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;While FID only measured the response speed of the very first user interaction, INP evaluates the responsiveness of all clicks, taps, and keyboard inputs across the entire lifecycle of the page visit. It logs the delay between an interaction and the subsequent visual update (the &amp;ldquo;Next Paint&amp;rdquo;).&lt;/p&gt;</description></item><item><title>CDN 快取策略：最大化效能和新鮮度</title><link>https://takao.blog/zh-tw/web/cdn-caching-strategies/</link><pubDate>Mon, 30 Dec 2024 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/cdn-caching-strategies/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/cdn-caching-strategies-zh-tw.png" alt="Featured image of post CDN 快取策略：最大化效能和新鮮度" /&gt;&lt;h2 id="介紹"&gt;介紹
&lt;/h2&gt;&lt;p&gt;內容交付網路 (CDN) 是現代 Web 效能的支柱。透過在全球分佈的邊緣節點快取內容，CDN 大大減少了延遲並卸載了來源伺服器的流量。然而，有效的快取並不僅僅是啟用 CDN 然後就忘記它的問題。在效能（高快取命中率和低延遲）與新鮮度（最小陳舊性和快速失效）之間取得適當的平衡需要深思熟慮的策略。&lt;/p&gt;
&lt;p&gt;本指南探討了 CDN 快取基礎、快取控制指令、代理鍵、失效策略、重新驗證時過時、多層快取和監控，提供您現在可以應用的實用方法。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="cdn-快取基礎知識"&gt;CDN 快取基礎知識
&lt;/h2&gt;&lt;p&gt;CDN 快取在邊緣節點儲存回應副本（存在積分或 POP），因此可以在不聯繫來源伺服器的情況下處理對相同資源的後續請求。 &lt;strong&gt;快取命中&lt;/strong&gt;時，回應將在 5-50 毫秒內提供。當&lt;strong&gt;快取未命中&lt;/strong&gt;時，請求將傳輸到來源，從而增加 100-500 毫秒的延遲。&lt;/p&gt;
&lt;p&gt;CDN 快取各種內容：靜態資產（圖片、CSS、JavaScript、字型）、API 回應（JSON、GraphQL）、HTML 頁面和串流內容。快取層次結構通常遵循邊緣節點→地方快取→來源屏蔽→來源伺服器。&lt;/p&gt;
&lt;p&gt;不同的 CDN 提供者有不同的快取理念和功能：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;供應商&lt;/th&gt;
					&lt;th&gt;快取控制&lt;/th&gt;
					&lt;th&gt;代理鍵&lt;/th&gt;
					&lt;th&gt;起源之盾&lt;/th&gt;
					&lt;th&gt;SWR 支援&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;雲耀&lt;/td&gt;
					&lt;td&gt;完整&lt;/td&gt;
					&lt;td&gt;快取標籤&lt;/td&gt;
					&lt;td&gt;Argo 分層快取&lt;/td&gt;
					&lt;td&gt;是的&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;快點&lt;/td&gt;
					&lt;td&gt;完整&lt;/td&gt;
					&lt;td&gt;代理鍵&lt;/td&gt;
					&lt;td&gt;快速盾&lt;/td&gt;
					&lt;td&gt;是的&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;阿卡邁&lt;/td&gt;
					&lt;td&gt;完整&lt;/td&gt;
					&lt;td&gt;快取標籤&lt;/td&gt;
					&lt;td&gt;物業經理&lt;/td&gt;
					&lt;td&gt;是的&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;雲前&lt;/td&gt;
					&lt;td&gt;完整&lt;/td&gt;
					&lt;td&gt;—&lt;/td&gt;
					&lt;td&gt;起源之盾&lt;/td&gt;
					&lt;td&gt;是的&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="深度快取控制指令"&gt;深度快取控制指令
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Cache-Control&lt;/code&gt; 標頭是指示 CDN 和瀏覽器如何快取回應的主要機制。了解其指令對於微調行為至關重要。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;max-age=&amp;lt;seconds&amp;gt;&lt;/code&gt;&lt;/strong&gt; — 指定資源保持新鮮的時間。對於像 &lt;code&gt;app.a1b2c3.js&lt;/code&gt; 這樣的版本化資產，請使用 &lt;code&gt;immutable&lt;/code&gt; 指令設定 &lt;code&gt;max-age=31536000&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;s-maxage=&amp;lt;seconds&amp;gt;&lt;/code&gt;&lt;/strong&gt; — 專門針對共用快取（CDN 和代理程式）覆寫 &lt;code&gt;max-age&lt;/code&gt;，讓您可以為 CDN 與瀏覽器設定不同的 TTL。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;public&lt;/code&gt; 與 &lt;code&gt;private&lt;/code&gt;&lt;/strong&gt; — &lt;code&gt;public&lt;/code&gt; 允許透過 CDN 和瀏覽器進行快取； &lt;code&gt;private&lt;/code&gt; 僅將快取限制在瀏覽器中，這對於特定於使用者的內容很重要。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;no-cache&lt;/code&gt; 與 &lt;code&gt;no-store&lt;/code&gt;&lt;/strong&gt; — &lt;code&gt;no-cache&lt;/code&gt; 允許緩存，但需要對每個請求重新驗證。 &lt;code&gt;no-store&lt;/code&gt; 完全禁止快取。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;stale-while-revalidate=&amp;lt;seconds&amp;gt;&lt;/code&gt;&lt;/strong&gt; — 立即提供過時的內容，同時在背景取得新內容。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;immutable&lt;/code&gt;&lt;/strong&gt; — 告訴瀏覽器資源在其新鮮生命週期內永遠不會改變，從而消除了條件重新驗證。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以下是針對不同內容類型的實用秘訣：&lt;/p&gt;</description></item><item><title>Mobile Web Performance 優化: 2024 技巧</title><link>https://takao.blog/zh-tw/web/mobile-performance/</link><pubDate>Thu, 26 Dec 2024 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/mobile-performance/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/mobile-performance-zh-tw.png" alt="Featured image of post Mobile Web Performance 優化: 2024 技巧" /&gt;&lt;h2 id="introduction"&gt;Introduction
&lt;/h2&gt;&lt;p&gt;Mobile web performance is no longer a secondary concern. With mobile traffic accounting for over 60% of global web traffic and growing rapidly in emerging markets, the performance characteristics of your site on mobile devices directly impact user retention, conversion, and search rankings. Users expect fast, fluid experiences — 53% abandon sites that take longer than 3 seconds to load. This article covers the key techniques for optimizing mobile web performance in 2024, from network-aware loading to touch event optimization and Core Web Vitals.&lt;/p&gt;</description></item><item><title>Node.js 效能監控：重要的指標</title><link>https://takao.blog/zh-tw/web/nodejs-performance/</link><pubDate>Wed, 18 Dec 2024 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/nodejs-performance/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/nodejs-performance-zh-tw.png" alt="Featured image of post Node.js 效能監控：重要的指標" /&gt;&lt;p&gt;Node.js 效能監控需要採用與傳統伺服器環境不同的方法。單線程事件循環、垃圾收集記憶體模型和非同步 I/O 創建了通用 CPU 和記憶體指標無法單獨捕獲的獨特故障模式。本文介紹了保持 Node.js 應用程式在生產環境中平穩運行所需的基本指標和工具。&lt;/p&gt;
&lt;h2 id="為什麼-nodejs-效能監控有所不同"&gt;為什麼 Node.js 效能監控有所不同
&lt;/h2&gt;&lt;p&gt;與多執行緒伺服器中緩慢的操作僅阻塞一個執行緒不同，Node.js 中的單一 CPU 密集型操作會阻塞整個事件循環，從而停止所有並發請求。垃圾收集暫停可能會導致不可預測的延遲高峰。常見的失敗模式包括事件循環飢餓、未清理的閉包導致的記憶體洩漏、回調抖動以及未處理的承諾拒絕默默吞下錯誤。了解這些特徵是有效監控的第一步。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="事件循環滯後"&gt;事件循環滯後
&lt;/h2&gt;&lt;p&gt;事件循環延遲測量調度計時器回呼與其實際執行之間的延遲。這是 Node.js 進程最重要的健康指標。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;monitorEventLoopDelay&lt;/span&gt; } &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;require&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;perf_hooks&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;histogram&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;monitorEventLoopDelay&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;histogram&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;enable&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// In your health check endpoint:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;setInterval&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lag&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;histogram&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;mean&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1e6&lt;/span&gt;; &lt;span style="color:#75715e"&gt;// Convert nanoseconds to milliseconds
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;histogram&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;reset&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;lag&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;50&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;logger&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;warn&lt;/span&gt;({ &lt;span style="color:#a6e22e"&gt;eventLoopLag&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;lag&lt;/span&gt; }, &lt;span style="color:#e6db74"&gt;&amp;#34;Event loop lag detected&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}, &lt;span style="color:#ae81ff"&gt;10000&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;滯後&lt;/th&gt;
					&lt;th&gt;解讀&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&amp;lt; 10 毫秒&lt;/td&gt;
					&lt;td&gt;健康&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;10–50 毫秒&lt;/td&gt;
					&lt;td&gt;關於 — 調查&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&amp;gt; 50 毫秒&lt;/td&gt;
					&lt;td&gt;關鍵－需要立即採取行動&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;常見原因包括同步 CPU 密集型操作、大負載上的過多 JSON 解析以及主執行緒中執行的資料庫查詢最佳化不佳。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="垃圾收集指標"&gt;垃圾收集指標
&lt;/h2&gt;&lt;p&gt;V8 的垃圾收集器分兩個階段運行：快速的清理（年輕代）和較慢的標記-清除-壓縮（老年代）。長時間或頻繁的 GC 暫停會直接影響 p99 延遲。&lt;/p&gt;</description></item><item><title>React 並發功能：建立響應式 UI</title><link>https://takao.blog/zh-tw/web/react-concurrent/</link><pubDate>Fri, 06 Dec 2024 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/react-concurrent/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/react-concurrent-zh-tw.png" alt="Featured image of post React 並發功能：建立響應式 UI" /&gt;&lt;p&gt;React 18 引入了並發功能，從根本上改變了渲染的工作方式。這些功能使 React 可以一次準備多個版本的 UI、中斷正在進行的工作，並優先考慮緊急更新而不是非緊急更新。結果是應用程式回應速度更快，而無需放棄使 React 高效的聲明式程式設計模型。&lt;/p&gt;
&lt;p&gt;React 中的並發不是一種全有或全無的模式。與早期實驗版本中廢棄的「並發模式」概念不同，React 18+ 選擇加入並發功能。您可以逐一採用它們，因為它們可以提供最大的價值。底層 Fiber 架構使這成為可能：React 的渲染階段可以暫停和恢復，因此協調器可以隨著優先順序的變化在不同的工作單元之間切換。&lt;/p&gt;
&lt;h2 id="使用轉換鉤子"&gt;使用轉換鉤子
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;useTransition&lt;/code&gt; 掛鉤可讓您將狀態更新標記為非緊急。這可以防止更新在關鍵用戶互動（例如打字）期間阻塞主執行緒。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;import&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;useTransition&lt;/span&gt; } &lt;span style="color:#a6e22e"&gt;from&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;react&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SearchPage&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; [&lt;span style="color:#a6e22e"&gt;isPending&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;startTransition&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;useTransition&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; [&lt;span style="color:#a6e22e"&gt;query&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;setQuery&lt;/span&gt;] &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;useState&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;handleChange&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;e&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Urgent: update the input value immediately
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;e&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;target&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;setQuery&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Non-urgent: filter the large dataset
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;startTransition&lt;/span&gt;(() =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;setFilter&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;div&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;query&lt;/span&gt;} &lt;span style="color:#a6e22e"&gt;onChange&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;handleChange&lt;/span&gt;} &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#a6e22e"&gt;isPending&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;Spinner&lt;/span&gt; &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;SearchResults&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;filter&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;{&lt;span style="color:#a6e22e"&gt;filter&lt;/span&gt;} &lt;span style="color:#f92672"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;/div&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; );
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;isPending&lt;/code&gt; 標誌提供了一種在不阻塞 UI 的情況下顯示載入指示器的方法。當 React 正在進行轉換時，&lt;code&gt;isPending&lt;/code&gt; 是 &lt;code&gt;true&lt;/code&gt;，使用者可以繼續鍵入，因為轉換可能會被更緊急的狀態更新中斷。&lt;/p&gt;</description></item><item><title>WebAssembly for Browser 使用法s: Beyond the Hype</title><link>https://takao.blog/zh-tw/web/wasm-browser-apps/</link><pubDate>Sat, 30 Nov 2024 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/wasm-browser-apps/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/wasm-browser-apps-zh-tw.png" alt="Featured image of post WebAssembly for Browser 使用法s: Beyond the Hype" /&gt;&lt;h2 id="introduction"&gt;Introduction
&lt;/h2&gt;&lt;p&gt;WebAssembly has matured from a niche curiosity into a production-ready tool for browser-based applications. While early demos focused on gaming engines and scientific simulations, today Wasm is used in image editors, video transcoders, compression libraries, and cryptographic utilities — all running in the browser at near-native speed.&lt;/p&gt;
&lt;p&gt;The key shift in 2024 is 生態系 maturity. WasmGC ships in Chrome 119+, SIMD is available across all major browsers, and reference types allow passing DOM nodes directly into Wasm modules. This article cuts through the hype to examine realistic use cases, compile-target decisions, memory management strategies, and integration patterns for production applications.&lt;/p&gt;</description></item><item><title>Third-Party Script 優化: Taming Page Bloat</title><link>https://takao.blog/zh-tw/web/third-party-scripts/</link><pubDate>Tue, 19 Nov 2024 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/third-party-scripts/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/third-party-scripts-zh-tw.png" alt="Featured image of post Third-Party Script 優化: Taming Page Bloat" /&gt;&lt;h2 id="introduction"&gt;Introduction
&lt;/h2&gt;&lt;p&gt;Third-party scripts are the hidden tax of modern web development. The average page loads 15–25 third-party requests, accounting for 60–80% of total page weight. Data from the HTTP Archive confirms that third-party JavaScript is growing faster than first-party code. Each external script adds network latency, parse and compile time, main-thread contention, and potential security risks. The good news: you can optimize third-party scripts without removing their functionality. The goal is to minimize performance impact while preserving business value.&lt;/p&gt;</description></item><item><title>JavaScript Bundle Size 優化: From Analysis to Action</title><link>https://takao.blog/zh-tw/web/bundle-size-optimization/</link><pubDate>Tue, 22 Oct 2024 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/bundle-size-optimization/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/bundle-size-optimization-zh-tw.png" alt="Featured image of post JavaScript Bundle Size 優化: From Analysis to Action" /&gt;&lt;p&gt;JavaScript bundle size directly impacts user experience. Larger bundles mean longer download times, slower parsing and compilation, and worse Core Web Vitals. A 100KB increase in JavaScript reduces conversion rates by 2 to 3 percent. Bundle optimization is an ongoing investment, not a one-time fix, and follows a cycle of analysis, identification, optimization, and monitoring.&lt;/p&gt;
&lt;h2 id="bundle-analysis-tools"&gt;Bundle Analysis Tools
&lt;/h2&gt;&lt;p&gt;Understanding what is in your bundle is the first step. webpack-bundle-analyzer provides an interactive treemap visualization that highlights large dependencies and duplicate modules. Vite users can leverage rollup-plugin-visualizer with sunburst and network graphs, while esbuild offers the &amp;ndash;metafile flag for detailed output analysis. source-map-explorer maps compiled code back to source files.&lt;/p&gt;</description></item><item><title>Image 優化 Strategies 2024: AVIF, WebP, and Beyond</title><link>https://takao.blog/zh-tw/web/image-optimization-2024/</link><pubDate>Tue, 02 Jul 2024 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/image-optimization-2024/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/image-optimization-2024-zh-tw.png" alt="Featured image of post Image 優化 Strategies 2024: AVIF, WebP, and Beyond" /&gt;&lt;h2 id="introduction"&gt;Introduction
&lt;/h2&gt;&lt;p&gt;Images account for over half of the typical webpage&amp;rsquo;s total weight. As web applications grow more visual, optimizing image delivery has become critical for performance, user experience, and Core Web Vitals scores. This article explores modern image optimization strategies, from next-generation formats to responsive delivery techniques.&lt;/p&gt;
&lt;h2 id="image-formats-in-2024"&gt;Image Formats in 2024
&lt;/h2&gt;&lt;p&gt;The image format landscape has shifted dramatically. Three modern formats now compete for dominance alongside legacy JPEG and PNG.&lt;/p&gt;</description></item><item><title>Node.js 工作執行緒：平行處理實踐</title><link>https://takao.blog/zh-tw/web/nodejs-worker-threads/</link><pubDate>Tue, 23 Apr 2024 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/nodejs-worker-threads/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/nodejs-worker-threads-zh-tw.png" alt="Featured image of post Node.js 工作執行緒：平行處理實踐" /&gt;&lt;p&gt;Node.js 傳統上是單線程的，並依賴非同步 I/O 來實現並發。雖然此模型擅長處理 I/O 密集型工作負載，但 CPU 密集型操作會阻止事件循環並降低應用程式回應能力。在 Node.js 12 中穩定的工作執行緒透過在單獨的 V8 隔離中執行 JavaScript 來在單一進程中提供真正的平行執行。本文介紹了在生產中使用工作執行緒的實用模式。&lt;/p&gt;
&lt;h2 id="工人生命週期和溝通"&gt;工人生命週期和溝通
&lt;/h2&gt;&lt;p&gt;建立工作執行緒需要一個單獨的 JavaScript 文件，該文件在自己的 V8 隔離中執行，並具有自己的堆和事件循環。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// main.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;Worker&lt;/span&gt; } &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;require&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;worker_threads&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;worker&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Worker&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;./worker.js&amp;#34;&lt;/span&gt;, {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;workerData&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;largeDataset&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;worker&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;on&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;message&amp;#34;&lt;/span&gt;, (&lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;logger&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;info&lt;/span&gt;({ &lt;span style="color:#a6e22e"&gt;result&lt;/span&gt; }, &lt;span style="color:#e6db74"&gt;&amp;#34;Worker completed&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;worker&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;on&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;error&amp;#34;&lt;/span&gt;, (&lt;span style="color:#a6e22e"&gt;err&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;logger&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;error&lt;/span&gt;({ &lt;span style="color:#a6e22e"&gt;err&lt;/span&gt; }, &lt;span style="color:#e6db74"&gt;&amp;#34;Worker failed&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;worker&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;on&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;exit&amp;#34;&lt;/span&gt;, (&lt;span style="color:#a6e22e"&gt;code&lt;/span&gt;) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;code&lt;/span&gt; &lt;span style="color:#f92672"&gt;!==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;logger&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;error&lt;/span&gt;({ &lt;span style="color:#a6e22e"&gt;exitCode&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;code&lt;/span&gt; }, &lt;span style="color:#e6db74"&gt;&amp;#34;Worker crashed&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// worker.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; { &lt;span style="color:#a6e22e"&gt;parentPort&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;workerData&lt;/span&gt; } &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;require&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;worker_threads&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;result&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;processData&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;workerData&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;input&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;parentPort&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;postMessage&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;result&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;工作人員透過結構化克隆進行通信，該克隆支援物件、陣列、Map、Sets、RegExp、Date 和 ArrayBuffers。對於大型二進位數據，請使用可傳輸物件來避免複製開銷 - 來源緩衝區在傳輸後會被中和。&lt;/p&gt;</description></item><item><title>Next.js Image 優化: From 設定 to 進階 Patterns</title><link>https://takao.blog/zh-tw/web/nextjs-image-optimization/</link><pubDate>Tue, 26 Mar 2024 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/nextjs-image-optimization/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/nextjs-image-optimization-zh-tw.png" alt="Featured image of post Next.js Image 優化: From 設定 to 進階 Patterns" /&gt;&lt;h2 id="introduction"&gt;Introduction
&lt;/h2&gt;&lt;p&gt;Images account for over 50% of total webpage bytes on average, making optimization essential for performance. Next.js provides a comprehensive image optimization pipeline through the &lt;code&gt;next/image&lt;/code&gt; component and its built-in Image Optimization API. This article covers setup, configuration, and advanced patterns with a focus on Core Web Vitals impact.&lt;/p&gt;
&lt;h2 id="the-nextimage-component"&gt;The next/image Component
&lt;/h2&gt;&lt;p&gt;The &lt;code&gt;next/image&lt;/code&gt; component extends the HTML &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; element with automatic optimization features: lazy loading, responsive srcset generation, width and height enforcement to prevent Cumulative Layout Shift, blur-up placeholders, and automatic format negotiation.&lt;/p&gt;</description></item><item><title>Core Web Vitals 優化: Complete 2024 指南</title><link>https://takao.blog/zh-tw/web/core-web-vitals/</link><pubDate>Mon, 15 Jan 2024 00:00:00 +0900</pubDate><guid>https://takao.blog/zh-tw/web/core-web-vitals/</guid><description>&lt;img src="https://takao.blog/img/thumbnail/core-web-vitals-zh-tw.png" alt="Featured image of post Core Web Vitals 優化: Complete 2024 指南" /&gt;&lt;p&gt;Core Web Vitals (CWV) are the set of user-centric performance metrics that Google uses to measure real-world experience on the web. In March 2024, Google replaced First Input Delay (FID) with Interaction to Next Paint (INP), making it critical to understand all three metrics: Largest Contentful Paint (LCP), INP, and Cumulative Layout Shift (CLS). This guide covers every aspect of optimizing your site for good CWV scores.&lt;/p&gt;
&lt;h2 id="understanding-core-web-vitals-in-2024"&gt;Understanding Core Web Vitals in 2024
&lt;/h2&gt;&lt;p&gt;The three CWV metrics measure distinct aspects of user experience. LCP tracks loading performance — how quickly the main content appears. INP measures interactivity — how responsive the page feels when users click, tap, or type. CLS quantifies visual stability — how much the layout shifts unexpectedly during load.&lt;/p&gt;</description></item></channel></rss>