js為什麼需要include?讓我們想想這樣1個場景,a.js 需要用到1個公用的common.js,當然你可以在用到a.js的頁面使用<script src="common.js">,但假設有5個頁面用到了a.js,你是不是要寫5遍<script。而且要是以後a.js 又需要引用common2.js,你是不是又的修改5個頁面了?
已有js include的一些問題
在寫這個之前在網上搜尋了些資料,發現以前寫的include都存在2個問題,這也是include需要解決的比較重要的2個問題。
1、相對路徑的問題: 在a.js中使用include("../js/common.js"); include 函數中肯定是使用相對路徑,是相對a.js的路徑。而a.js在html中使用<script>嵌入有可能是相對路徑,有可能是絕對路徑。 include函數如何才能真正确定common.js的絕對路徑,或者是相對html的相對路徑。網上一些為了解決這個問題,還需要加一些js變量,不友善。
2、引用的問題。 網上include函數的實作幾乎都是使用下面2種方式插入common.js
document.write("<script src='" + .. + "></script>")
或者
var s = document.createElement("script");
s.src = ...;
head.insertAfter(s,...);
document.write 輸出的腳本會在a.js後面加載,而createElement("script")建立的腳本是非阻塞加載。 是以如果在common.js加載完畢之前,a.js中調用了common.js的函數就會報錯。
實作
解決上面2個問題,就可以實作js include。
第1個問題,我的方法是先擷取到a.js在html中的絕對路徑(如果是相對路徑,就轉為絕對路徑),然後再把common.js的路徑轉為絕對路徑。
第2個問題,采用同步的ajax來請求common.js,這樣就不會出現引用問題。
實作代碼如下:
<code>// 根據相對路徑擷取絕對路徑</code>
<code>function</code> <code>getPath(relativePath,absolutePath){</code>
<code> </code><code>var</code> <code>reg =</code><code>new</code> <code>RegExp(</code><code>"\\.\\./"</code><code>,</code><code>"g"</code><code>);</code>
<code> </code><code>var</code> <code>uplayCount = 0; </code><code>// 相對路徑中傳回上層的次數。</code>
<code> </code><code>var</code> <code>m = relativePath.match(reg);</code>
<code> </code><code>if</code><code>(m) uplayCount = m.length;</code>
<code> </code>
<code> </code><code>var</code> <code>lastIndex = absolutePath.length-1;</code>
<code> </code><code>for</code><code>(</code><code>var</code> <code>i=0;i<=uplayCount;i++){</code>
<code> </code><code>lastIndex = absolutePath.lastIndexOf(</code><code>"/"</code><code>,lastIndex);</code>
<code> </code><code>}</code>
<code> </code><code>return</code> <code>absolutePath.substr(0,lastIndex+1) + relativePath.replace(reg,</code><code>""</code><code>);</code>
<code>} </code>
<code>function</code> <code>include(jssrc){</code>
<code> </code><code>// 先擷取目前a.js的src。a.js中調用include,直接擷取最後1個script标簽就是a.js的引用。</code>
<code> </code><code>var</code> <code>scripts = document.getElementsByTagName(</code><code>"script"</code><code>);</code>
<code> </code><code>var</code> <code>lastScript = scripts[scripts.length-1];</code>
<code> </code><code>var</code> <code>src = lastScript.src;</code>
<code> </code><code>if</code><code>(src.indexOf(</code><code>"http://"</code><code>)!=0 && src.indexOf(</code><code>"/"</code><code>) !=0){ </code>
<code> </code><code>// a.js使用相對路徑,先替換成絕對路徑</code>
<code> </code><code>var</code> <code>url = location.href;</code>
<code> </code><code>var</code> <code>index = url.indexOf(</code><code>"?"</code><code>);</code>
<code> </code><code>if</code><code>(index != -1){</code>
<code> </code><code>url = url.substring(0, index-1);</code>
<code> </code><code>}</code>
<code> </code>
<code> </code><code>src = getPath(src,url);</code>
<code> </code><code>var</code> <code>jssrcs = jssrc.split(</code><code>"|"</code><code>); </code><code>// 可以include多個js,用|隔開</code>
<code> </code><code>for</code><code>(</code><code>var</code> <code>i=0;i<jssrcs.length;i++){</code>
<code> </code><code>// 使用juqery的同步ajax加載js.</code>
<code> </code><code>// 使用document.write 動态添加的js會在目前js的後面,可能會有js引用問題</code>
<code> </code><code>// 動态建立script腳本,是非阻塞下載下傳,也會出現引用問題</code>
<code> </code><code>$.ajax({type:</code><code>'GET'</code><code>,url:getPath(jssrc,src),async:</code><code>false</code><code>,dataType:</code><code>'script'</code><code>});</code>
<code>}</code>
在a.js中直接使用 include("../js/common.js");
多請求的問題
使用上面的include看上去挺爽的,不過卻帶來另外1個嚴重的問題,就是多發送了1個ajax的請求。
我們常常為了WEB性能,而合并js,減少請求。但使用include後卻偏偏多了請求。如果這個問題不解決,相信很多人都不會在正式産品中使用include的了,除非是區域網路産品。
如何解決這個多請求的問題,我也思考很久,最後覺的單單使用用戶端js是沒辦法解決了。是以就想到了使用服務端代碼來解決
是以我把include多請求的解決方案也加到裡面去。就是在程式啟動的時候去查找所有的js,發現有使用include的就把include中common.js的源代碼替換該include函數。這樣a.js中在運作的時候就沒有include函數,而是真真包含了common.js的内容的js檔案
後語
丫的。說到最後,怎麼又把所有的include都替換掉了,哪之前說的那麼多不白說了。
個人覺得,每個産品都應該要區分開發環境和産品環境(一般通過配置檔案進行區分),在開發環境應該以開發效率為首要,而産品環境則以性能為首。是以這裡的inlcude就應該要區分對待,在開發環境中使用js include來提高開發和維護效率,而在産品環境中則自動把所有include替換成真真的js檔案的内容。
本文轉自BearRui(AK-47)部落格園部落格,原文連結: http://www.cnblogs.com/BearsTaR/archive/2010/08/05/js_include.html ,如需轉載請自行聯系原作者