在開發 Node.js 應用程式時,效能瓶頸往往不易察覺。幸運的是,Node.js 提供了內建的 Profiler,可以幫助我們找出程式的效能瓶頸並進行優化。本文將分享我在使用 Node.js Profiler 進行效能優化的經驗。
如何使用 Node.js Profiler
可以使用 node --inspect-brk
啟動應用程式,並透過 Chrome DevTools 進行分析:
node --inspect-brk somefile.js
執行後打開 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 .
在報告中,我發現名為 isCreateElement
的函數佔用了約 5% 的執行時間,這成為潛在的優化目標:
優化過程
檢視原始碼後發現,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;
}
};
我們將 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;
}
};
優化結果
重新運行 Profiler 後,發現 isCreateElement
的執行時間從 5% 大幅下降至 0.0%:
這次優化顯示即便是微小的程式碼調整,也能帶來顯著的效能提升。
更多優化案例
在 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
可以幫助你鎖定潛在效能問題,並且提供量化數據來評估改善的成效。
Top comments (0)