DEV Community

Cover image for 利用 Node.js Profiler 改善程式效能
Chiawen Chen
Chiawen Chen

Posted on

利用 Node.js Profiler 改善程式效能

在開發 Node.js 應用程式時,效能瓶頸往往不易察覺。幸運的是,Node.js 提供了內建的 Profiler,可以幫助我們找出程式的效能瓶頸並進行優化。本文將分享我在使用 Node.js Profiler 進行效能優化的經驗。

如何使用 Node.js Profiler

可以使用 node --inspect-brk 啟動應用程式,並透過 Chrome DevTools 進行分析:

node --inspect-brk somefile.js
Enter fullscreen mode Exit fullscreen mode

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

Flame Graph 提供兩種常見檢視方式:

  • 按執行順序檢視:檢視程式的執行路徑,幫助理解函數呼叫的流程。
  • 依函數聚合檢視:統計每個函數的總執行時間,幫助快速找出效能瓶頸。

範例:優化 eslint-plugin-react

eslint-plugin-react 為例,這是一個用於 React 的 ESLint 插件。我們在進行分析時,使用如下指令啟動 Profiler:

node --inspect-brk node_modules/.bin/eslint .
Enter fullscreen mode Exit fullscreen mode

在報告中,我發現名為 isCreateElement 的函數佔用了約 5% 的執行時間,這成為潛在的優化目標:

profiler_report1flame_graph

優化過程

檢視原始碼後發現,isCreateElement 函數在每次呼叫時都進行了一次昂貴的運算 pragmaUtil.getFromContext(context)

module.exports = function isCreateElement(node, context) {
  const pragma = pragmaUtil.getFromContext(context);
  if (
    node.callee &&
    node.callee.type === 'MemberExpression' &&
    node.callee.property.name === 'createElement' &&
    node.callee.object &&
    node.callee.object.name === pragma
  ) {
    return true;
  }
};
Enter fullscreen mode Exit fullscreen mode

我們將 pragmaUtil.getFromContext(context) 的呼叫直接移到條件判斷的尾端,讓他有機會被 short-circuit,避免執行:

module.exports = function isCreateElement(node, context) {
  if (
    node.callee &&
    node.callee.type === 'MemberExpression' &&
    node.callee.property.name === 'createElement' &&
    node.callee.object &&
    node.callee.object.name === pragmaUtil.getFromContext(context)
  ) {
    return true;
  }
};
Enter fullscreen mode Exit fullscreen mode

優化結果

重新運行 Profiler 後,發現 isCreateElement 的執行時間從 5% 大幅下降至 0.0%:

這次優化顯示即便是微小的程式碼調整,也能帶來顯著的效能提升。

profiler_report2

更多優化案例

在 2022 年,我持續對 eslint-plugin-react 進行了多項效能優化,以下是部分 Pull Request:

[Refactor]: improve performance for detecting function components

[Refactor] improve performance for detecting class components

[Refactor] no-deprecated: improve performance

[Refactor] no-*-set-state: improve performance

[Refactor] improve performance by avoiding unnecessary component detect

[Refactor] improve performance of component detection

[Refactor] improve performance of rule merging

[Perf] improve performance for rules using isCreateElement

[Perf] improve performance by optimizing getId

[Perf] component detection: improve performance by avoiding traversing parents unnecessarily

透過這些優化,eslint 在一個私人專案中的執行時間從 8.7 秒減少至 3.6 秒,效能提升了 141%。

結語

node --inspect-brk 可以幫助你鎖定潛在效能問題,並且提供量化數據來評估改善的成效。

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay