Re: [問題] 有架構化的Java Script

看板Ajax作者 (鼎玉鉉)時間15年前 (2010/09/26 02:45), 編輯推噓1(106)
留言7則, 3人參與, 最新討論串5/5 (看更多)
※ 引述《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="" rel="nofollow">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

09/26 08:01, , 1F
以現在的速度 載第一頁就要數分鐘有點誇大了 是數秒鐘
09/26 08:01, 1F

09/26 09:37, , 2F
我都用Math.round(Math.random() * 1000)
09/26 09:37, 2F

09/26 13:26, , 3F
而且如果搭配把script 放在 </body> 前 對大部分頁面來講
09/26 13:26, 3F

09/26 13:26, , 4F
幾乎是無感(除非你倚賴js做進場動畫...)。而且比起每次都
09/26 13:26, 4F

09/26 13:26, , 5F
要分開讀取檔案,打成一包的traffic 搭配cache效果反而更好.
09/26 13:26, 5F

09/26 13:28, , 6F
另外舅是通常大部分狀況下,重新載入是不需要,多是給版本號
09/26 13:28, 6F

09/26 13:28, , 7F
要用這個作法,我比較推薦 using.js 。
09/26 13:28, 7F
文章代碼(AID): #1CdaD43O (Ajax)
文章代碼(AID): #1CdaD43O (Ajax)