項目背景
後臺在管理界面直接編輯js,然後前端直接運行加載此 js,並且此頁面不會刷新(指定的 F5 這種刷新),而且是一直投影在屏幕上的。其中 js 分2部分,一部分是相對固定。一部分是動態的。前端通用不停的獲取後臺的 js 然後在實例化 js 來動態更新界面數據。
方案
直接使用 new Function
來動態解析後臺填寫的 js 腳本。demo 如下
<html>
<head>
<h1></h1>
</head>
<script>
//轉換函數
var convertToFn = function (fun) {
return (new Function("return " + fun))();
}
var i = 0;
setInterval(function(){
var fn = convertToFn("{\
thisMap : {\
thisFn : function(){\
return 'aaa'\
}\
}\
}");
fn.thisMap.thisFn();
i++;
document.getElementsByTagName("h1")[0].innerHTML = i;
// console.log(fn.thisMap.thisFn())
}, 10);
</script>
</html>
項目上線後發現此方法非常損耗內存。上面的函數循環大約20000次之後佔用內存 11MB 左右。並且一直不會釋放。從而導致瀏覽器內存耗盡奔潰。下圖有快照。
20000次很快就花完的了,而且設置的是4秒一次。又不止一個圖形在刷,有20+個。
曲線救國
不在支持動態刷新固定的部分的 js,只做值的動態更新。進一步驗證之後,此方式是可以有效控制內存不增長。demo 如下
<html>
<head>
<h1></h1>
</head>
<script>
//先使用 el 表達式輸出到界面(或者使用 document.write 輸出,再不濟就用上面的 new Function 吧,只輸出一次就好 )
var data = {};
var fn = function(){
return {
thisMap : {
thisFn : function(){
return 'aaa'
},
getData : data
}
}
}
var i = 0;
setInterval(function(){
//賦值給此變量,後面調用的時候就可以拿到最新的了
data = Math.random(1000000)*100;
i++;
document.getElementsByTagName("h1")[0].innerHTML = i;
// console.log(fn().thisMap.getData)
}, 10);
</script>
</html>
下圖爲內存快照,開始有增長,後面基本就沒有了