<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Chiawen Chen</title>
    <description>The latest articles on DEV Community by Chiawen Chen (@chiawend).</description>
    <link>https://dev.to/chiawend</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F40750%2Fbf222290-7ebd-4bd0-bc9d-0d88e83b0d6c.jpg</url>
      <title>DEV Community: Chiawen Chen</title>
      <link>https://dev.to/chiawend</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chiawend"/>
    <language>en</language>
    <item>
      <title>利用 Node.js Profiler 改善程式效能</title>
      <dc:creator>Chiawen Chen</dc:creator>
      <pubDate>Thu, 06 Feb 2025 07:30:00 +0000</pubDate>
      <link>https://dev.to/chiawend/li-yong-nodejs-profiler-gai-shan-cheng-shi-xiao-neng-c2l</link>
      <guid>https://dev.to/chiawend/li-yong-nodejs-profiler-gai-shan-cheng-shi-xiao-neng-c2l</guid>
      <description>&lt;p&gt;在開發 Node.js 應用程式時，效能瓶頸往往不易察覺。幸運的是，Node.js 提供了內建的 Profiler，可以幫助我們找出程式的效能瓶頸並進行優化。本文將分享我在使用 Node.js Profiler 進行效能優化的經驗。&lt;/p&gt;

&lt;h1&gt;
  
  
  如何使用 Node.js Profiler
&lt;/h1&gt;

&lt;p&gt;可以使用 &lt;code&gt;node --inspect-brk&lt;/code&gt; 啟動應用程式，並透過 Chrome DevTools 進行分析：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node --inspect-brk somefile.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;執行後打開 Chrome DevTools 點擊 DevTools for Node，進入 Performance 面板後，點擊錄製按鈕來進行效能分析。完成後會產生一張 Flame Graph，顯示各個函數的執行時間與呼叫堆疊。&lt;/p&gt;

&lt;p&gt;Flame Graph 提供兩種常見檢視方式：&lt;/p&gt;

&lt;ul&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;/ul&gt;

&lt;h1&gt;
  
  
  範例：優化 eslint-plugin-react
&lt;/h1&gt;

&lt;p&gt;以 &lt;code&gt;eslint-plugin-react&lt;/code&gt; 為例，這是一個用於 React 的 ESLint 插件。我們在進行分析時，使用如下指令啟動 Profiler：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node --inspect-brk node_modules/.bin/eslint .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;在報告中，我發現名為 &lt;code&gt;isCreateElement&lt;/code&gt; 的函數佔用了約 5% 的執行時間，這成為潛在的優化目標：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx0t8ldfseu9g9f34ushy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx0t8ldfseu9g9f34ushy.png" alt="profiler_report1" width="800" height="203"&gt;&lt;/a&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzgp97xehkf8a75yt2hjj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzgp97xehkf8a75yt2hjj.png" alt="flame_graph" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  優化過程
&lt;/h1&gt;

&lt;p&gt;檢視原始碼後發現，&lt;code&gt;isCreateElement&lt;/code&gt; 函數在每次呼叫時都進行了一次昂貴的運算 &lt;code&gt;pragmaUtil.getFromContext(context)&lt;/code&gt;：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isCreateElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pragma&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pragmaUtil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFromContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callee&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MemberExpression&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;createElement&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;pragma&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;我們將 &lt;code&gt;pragmaUtil.getFromContext(context)&lt;/code&gt; 的呼叫直接移到條件判斷的尾端，讓他有機會被 short-circuit，避免執行：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isCreateElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callee&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MemberExpression&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;createElement&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;pragmaUtil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFromContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  優化結果
&lt;/h1&gt;

&lt;p&gt;重新運行 Profiler 後，發現 &lt;code&gt;isCreateElement&lt;/code&gt; 的執行時間從 5% 大幅下降至 0.0%：&lt;/p&gt;

&lt;p&gt;這次優化顯示即便是微小的程式碼調整，也能帶來顯著的效能提升。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvs6p6jko8easnfj428fc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvs6p6jko8easnfj428fc.png" alt="profiler_report2" width="800" height="152"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  更多優化案例
&lt;/h1&gt;

&lt;p&gt;在 2022 年，我持續對 &lt;code&gt;eslint-plugin-react&lt;/code&gt; 進行了多項效能優化，以下是部分 Pull Request：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jsx-eslint/eslint-plugin-react/pull/3265" rel="noopener noreferrer"&gt;[Refactor]: improve performance for detecting function components&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jsx-eslint/eslint-plugin-react/pull/3267" rel="noopener noreferrer"&gt;[Refactor] improve performance for detecting class components&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jsx-eslint/eslint-plugin-react/pull/3271" rel="noopener noreferrer"&gt;[Refactor] &lt;code&gt;no-deprecated&lt;/code&gt;: improve performance&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jsx-eslint/eslint-plugin-react/pull/3272" rel="noopener noreferrer"&gt;[Refactor] &lt;code&gt;no-*-set-state&lt;/code&gt;: improve performance&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jsx-eslint/eslint-plugin-react/pull/3273" rel="noopener noreferrer"&gt;[Refactor] improve performance by avoiding unnecessary component detect&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jsx-eslint/eslint-plugin-react/pull/3276" rel="noopener noreferrer"&gt;[Refactor] improve performance of component detection&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jsx-eslint/eslint-plugin-react/pull/3281" rel="noopener noreferrer"&gt;[Refactor] improve performance of rule merging&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jsx-eslint/eslint-plugin-react/pull/3450" rel="noopener noreferrer"&gt;[Perf] improve performance for rules using isCreateElement&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jsx-eslint/eslint-plugin-react/pull/3451" rel="noopener noreferrer"&gt;[Perf] improve performance by optimizing getId&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jsx-eslint/eslint-plugin-react/pull/3459" rel="noopener noreferrer"&gt;[Perf] component detection: improve performance by avoiding traversing parents unnecessarily&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;透過這些優化，&lt;code&gt;eslint&lt;/code&gt; 在一個私人專案中的執行時間從 8.7 秒減少至 3.6 秒，效能提升了 141%。&lt;/p&gt;

&lt;h1&gt;
  
  
  結語
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;node --inspect-brk&lt;/code&gt; 可以幫助你鎖定潛在效能問題，並且提供量化數據來評估改善的成效。&lt;/p&gt;

</description>
      <category>node</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
