前言
最近另一個專案的網站一上線馬上就崩潰了,紀錄一下關於效能上的解決方法。
問題
該網站的效能瓶頸在於會載入大量js寫成的動畫效果,因此利用模組化將程式碼拆開且動態載入需要的效果即可。
使用createElement
產生script
,再綁定load
事件來偵測是否載入完畢達到非同步的效果。
1 2 3 4 5 6 7 8
| var jsFile = document.createElement("script"); jsFile.setAttribute("type","text/javascript"); jsFile.setAttribute("src", "js/jquery.js"); document.getElementsByTagName("head")[0].appendChild(jsFile); jsFile.addEventListener("load",function(){ console.log($); })
|
AMD
若是像以前在HTML逐步利用tag載入script,這樣子同步載入會照成阻塞以及非必要的載入,而AMD ( Asynchronous Module Definition ) 就是希望可以達到模組化以及異步載入的效果。
RequireJS
若不想像這樣一個一個綁事件,則可以利用RequireJS這個函式庫達到AMD的效果。
在HTML中設置data-main
屬性註明主要的js檔(.js可省略),defer
和async="true"
則是註明需要異步載入(非必需)。
1
| <script src="js/require.js" defer async="true" data-main="/js/main" ></script>
|
使用require
函數載入模組,可利用陣列一次載入多個模組。
1 2 3
| require(['jquery'], function ($){ console.log($); });
|
若想要將模組導出,則要使用define
函數。
1 2 3 4 5 6 7 8 9 10 11 12 13
| define(function (){ var getName = function(){ return "Jeno" ; } return { getName : getName } }); require(['module1'],function(m1){ console.log(m1.getName); })
|
若這個要導出的模組同時需要依賴其他模組,將define
第一個參數如同require
使用。
1 2 3 4 5 6 7 8 9
| define(['jquery'],function ($){ var getName = function(){ return "Jeno" ; } return { getName : getName } });
|
ES6
ES6中則是直接新增了import
及export
來使用模組。
利用export
導出模組。
1 2 3 4 5 6 7 8
| export default getName(){ return "Jeno" ; } export function getWord() { return "Hello" ; }
|
利用import
導入模組。
1 2
| import foo from './module1.js' ; foo();
|
載入模組特定的元素
1 2 3
| import { getName , getWord } from './module1.js' ; getName(); getWord();
|
載入模組所有元素
1 2 3
| import * as Module1 from './module1.js' ; Module1.default(); Module1.getWord();
|
結果
調校前
調校後
原本大概50人左右反應時間就需要20秒左右,改善後則是50人也不超過2秒,沒想到人數一多在效能上會有如此大的差距!
壓力測試
Load Impact是個免費壓力測試的服務,超過一定次數或者需要更高的要求則需要付費。
Slow Query Log
MySQL
可以在my.cnf
加入設定記錄較慢的query。
1 2 3
| slow_query_log = 1 //開啟設定 slow_query_log_file = /var/log/mysql-slow.log //log檔位置 long_query_time = 1 //超出幾秒儲存
|
Time Log Pivot
在程式執行間隔前後紀錄當下時間,利用差值則可找出程式的效能瓶頸。