作者sk1765 (鼎玉铉)
看板Ajax
标题Re: [问题] 有架构化的Java Script
时间Sun Sep 26 02:45:21 2010
※ 引述《liaosankai (低温烘焙)》之铭言:
: 关於这个问题,我也是有相同的经验。最主要是因为javascript虽然可以单独
: 写成一个js档,再透过<script>标签读入,来达成某个程度上的程式码管理,
: 但是你必须清楚的知道每个独立的js档案是否有用到其他js档,如果有则必须
: 一并为需要的JS档加上<script>标签来读入。而不是像一般的程式语言有汇入
: 其他档案的语法,像c++的include或java的import可以使用,所以当一个专案
: 变得很大的时候,通常最後为了能让网页正确执行,都会把所有js档全部读入
: 或全部集中成一个js档,但日後的如果有更新,势必要再把所有档案集中压缩
: 一次。
: 针对这个问题我尝试用过动态产生<script>来模拟import的方法,但是很遗憾
: 的,javascript是个直译式的语言,所以他并不会等待<script>建立完成才继
: 续下一段程式码,以下面为例子,假设Include函式实作了一个功能:
: 建立<scirpt>,指定参数为url,并将<script>加入<head>的相关程式码。
: global.js 定义了某些变数:
: ----------------------------------------------------------------
: var name = 'Kai';
: ----------------------------------------------------------------
: index.html 的javascript内容:
: ----------------------------------------------------------------
: <script src="http://localhost/js/Include.js"></script>
: <script>
: function sayHello()[
: alert('hello, ' + name);
: }
: Include('http://localhost/js/global.js');
: sayHello();
: </script>
: ----------------------------------------------------------------
: 我们尝试呼叫位於另一个js档案所宣告的name变数,你期望应该看到的是
: hello, Kai
: 但是浏览器会很残酷的跟你说没有这个东东,跑出变数未定义的大错误,因为
: sayHello()并不会等待 Include()的完成,就会立刻执行,这结果相当令人沮
: 丧,但是如果你尝试延迟执行函式:
: setTimeout('sayHello()', 1000);
: 你就能看到与预期相符的结果,表示档案确实是有被读入,也有完成程式码的
: 执行,但是我们没办法限制程式码的执行顺序。
: 最後透过不同的逻辑方式,我尝试成功实作了档案汇入的机制,当然在规则上
: 有其一定的限制,但在执行上确实能达到档案组织管理的好处,不妨可以参考
: 看看或互相交流讨论,提供更好的意见
: 专案位置
: http://code.google.com/p/jclassscript/
Include('
http://localhost/js/global.js');
这有个专用名词 On-Demand Javascript
这在javascript的领域里是一门很高深的学问
意思即在 javascript程式码片段 在需要的时候才载入
举凡 按下一个button的时候 在event handler中 才去载入一个动画的.js
在login的画面 按下submit 才去载入整个login.js
为什麽要这样做 无非是降低频宽的使用量 以及使用者的流畅性
如果把javascript打包成一整包 在第一页就载入 那麽第一页可能要花上数分钟
尤其是一些 framework 可能是非常fat的
而每一页的button 有可能使用者并不都会去按 那麽载入一个完整的js
无疑是另外一种浪费 想像一下把fckeditor整个编辑器载入要花多少时间
若是使用者根本没有编辑文件 那麽这个载入就太笨了
On-Demand Javascript在 Ajax Design Patterns一书第六章有完整的介绍
这跟import的差距是非常大的import是在compiler之前 而On-Demand则是在解译之後
以下提供一段程式码供各位参考
function LoadScript( url ){
var httpRequest = createXMLHttpRequest();
httpRequest.open("GET",url,false);
httpRequest.send(null); //send要加null否则ff不work
var script = httpRequest.responseText;
//以下适用各种浏览器ondemand js 解决方法从ajaxian获得解答
//IE对eval()完全无法建置在全域下 所以改用execScript
if (window.execScript) {
window.execScript(script); // eval in global scope for IE }
else {
with(window) {
window.eval(script);
}
}
}
function createXMLHttpRequest() {
try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch(e) {}
try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch(e) {}
try { return new XMLHttpRequest(); } catch(e) {}
alert("XMLHttpRequest not supported");
return null;
}
其中重要的关键在
httpRequest.open("GET",url,false);
我是用false 所以程式码一定在完整回传之後 javascript才会做下一件事
而不是非同步呼叫 当然啦如果想要背景载入 也可以用非同步的方式
: <script>
: function sayHello()[
: alert('hello, ' + name);
: }
: Include('http://localhost/js/global.js');
: sayHello();
: </script>
这段程式并不会不能执行 function在载入的时机是死的 直到加了()才会执行
所以 sayHello() {...........} 这段并不会在载入时机执行
问题出在sayHello();
如果将sayHello();直接写在javascript 当然javascript哪时候载入 就会哪时候执行到
因此必须将sayHello(); 写在onload的时机
onload发生在所有页面及js载入後
只需把程式改成
window.onload = init;
function init() {
Include('
http://localhost/js/global.js');
sayHello();
}
那麽先载入的function sayHello也是正常的 有关载入时机请参阅ppk on javascript 4-E
另外Include('
http://localhost/js/global.js'); 改成
Include('
http://localhost/js/global.js?' + ( new Date() * 1) );
会更好 加了一个不断随时间改变的querystring 会使的url变的不同
那麽.js档 就会是最新的啦 因为浏览器的判断是否要重新载入网页 是依照网址是否相同
我通常在网页的开始只载入依些基本的util.js 还有上述段LoadScript utility
其他的功能都分散在各小段的js档 直到使用者要用到时才呼叫
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 203.70.98.144
1F:→ ileadu:以现在的速度 载第一页就要数分钟有点夸大了 是数秒钟 09/26 08:01
2F:推 s25g5d4:我都用Math.round(Math.random() * 1000) 09/26 09:37
3F:→ TonyQ:而且如果搭配把script 放在 </body> 前 对大部分页面来讲 09/26 13:26
4F:→ TonyQ:几乎是无感(除非你倚赖js做进场动画...)。而且比起每次都 09/26 13:26
5F:→ TonyQ:要分开读取档案,打成一包的traffic 搭配cache效果反而更好. 09/26 13:26
6F:→ TonyQ:另外舅是通常大部分状况下,重新载入是不需要,多是给版本号 09/26 13:28
7F:→ TonyQ:要用这个作法,我比较推荐 using.js 。 09/26 13:28