[Web] AMD及效能調校

前言

最近另一個專案的網站一上線馬上就崩潰了,紀錄一下關於效能上的解決方法。

問題

該網站的效能瓶頸在於會載入大量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可省略),deferasync="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
// module1.js
define(function (){
var getName = function(){
return "Jeno" ;
}
return {
getName : getName
}   
});
// main.js
require(['module1'],function(m1){
console.log(m1.getName); // Jeno
})

若這個要導出的模組同時需要依賴其他模組,將define第一個參數如同require使用。

1
2
3
4
5
6
7
8
9
// module1.js
define(['jquery'],function ($){
var getName = function(){
return "Jeno" ;
}
return {
getName : getName
}   
});

ES6

ES6中則是直接新增了importexport來使用模組。

利用export導出模組。

1
2
3
4
5
6
7
8
// module1.js
// default代表預設導出
export default getName(){
return "Jeno" ;
}
export function getWord() {
return "Hello" ;
}

利用import導入模組。

1
2
import foo from './module1.js' ;
foo(); //Jeno

載入模組特定的元素

1
2
3
import { getName , getWord } from './module1.js' ;
getName(); //Jeno
getWord(); //Hello

載入模組所有元素

1
2
3
import * as Module1 from './module1.js' ;
Module1.default(); //Jeno
Module1.getWord(); //Hello

結果

調校前

調校後

原本大概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

在程式執行間隔前後紀錄當下時間,利用差值則可找出程式的效能瓶頸。