天天看點

requirejs中非AMD規範js的加載

我們知道在javascript中定義全局變量有2種方式,本質上是等價的,都是向window對象注入屬性或者方法。

// global.js

var g_name = "aty";

window.g_age = 25;
           

當global.js加載的時候,浏覽器的全局對象window就會多出2個屬性:g_name和g_age。

我們編寫一個js工具類或者是js架構,通常有2種方式:

方式1:dateUtil.js

(function(window) {
 
	var DateUtils = {};
	
	DateUtils.toString = function(){
		alert("toString");
	};
 
	// 全局變量
	window.DateUtils = DateUtils;
  
})(window);
           

這種方式是最常用的,比如JQuery、Underscore等架構都是采用這種結構編寫的。

方式2:stringUtil.js

// 全局變量
var StringUtils = {};


StringUtils.toUpperCase = function(input){
	alert("toUpperCase");
}
           

很顯然string Util.js和dateUtil.js都不符合AMD規範,現在我們看看如何通過requireJS進行加載。工程目錄結構如下:

index.html
main.js
libs
	--dateUtil.js
	--stringUtil.js
           

index.html和main.js的實作代碼如下:

<!doctype html>
<html>
    <<span id="16_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="16_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?app_id=0&c=news&cf=1001&ch=0&di=128&fv=17&is_app=0&jk=1b73df95847a2cfc&k=head&k0=head&kdi0=0&luki=7&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=fc2c7a8495df731b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D671521%2Ehtml&urlid=0" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" mpid="16" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">head</span></a></span>>
        <title>shim</title>
        <meta charset="utf-8">
        <script data-main="main.js" <span id="17_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="17_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?app_id=0&c=news&cf=1001&ch=0&di=128&fv=17&is_app=0&jk=1b73df95847a2cfc&k=src&k0=src&kdi0=0&luki=5&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=fc2c7a8495df731b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D671521%2Ehtml&urlid=0" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" mpid="17" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">src</span></a></span>="./../requirejs-2.1.15.js"></script>
    </head>
    <body>
		<div id="div1" <span id="18_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="18_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?app_id=0&c=news&cf=1001&ch=0&di=128&fv=17&is_app=0&jk=1b73df95847a2cfc&k=style&k0=style&kdi0=0&luki=6&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=fc2c7a8495df731b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D671521%2Ehtml&urlid=0" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" mpid="18" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">style</span></a></span>="width:200px;height:200px;background-color:#465ae0;"></div>
     
    </body>
</<span id="19_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="19_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?app_id=0&c=news&cf=1001&ch=0&di=128&fv=17&is_app=0&jk=1b73df95847a2cfc&k=html&k0=html&kdi0=0&luki=3&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=fc2c7a8495df731b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D671521%2Ehtml&urlid=0" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" mpid="19" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">html</span></a></span>>
           
requirejs.config({
    baseUrl: 'libs'
});


require(["dateUtil","stringUtil"], function(dateUtil,stringUtil) {
    
	alert(dateUtil===undefined);//true

});
           

運作index.html,通過F12觀察:

requirejs中非AMD規範js的加載

很明顯dateUtil.js和stringUtil.js能夠被requireJS正常加載,但是不能擷取到這2個子產品的傳回值。我們修改下index.html,給div注冊事件處理函數,并在事件處理函數中調用stringUtil.js提供的方法:

<!doctype html>
<html>
    <<span id="12_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="12_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?app_id=0&c=news&cf=1001&ch=0&di=128&fv=17&is_app=0&jk=1b73df95847a2cfc&k=head&k0=head&kdi0=0&luki=7&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=fc2c7a8495df731b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D671521%2Ehtml&urlid=0" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" mpid="12" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">head</span></a></span>>
        <title>shim</title>
        <meta charset="utf-8">
        <script data-main="main.js" <span id="13_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="13_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?app_id=0&c=news&cf=1001&ch=0&di=128&fv=17&is_app=0&jk=1b73df95847a2cfc&k=src&k0=src&kdi0=0&luki=5&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=fc2c7a8495df731b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D671521%2Ehtml&urlid=0" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" mpid="13" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">src</span></a></span>="./../requirejs-2.1.15.js"></script>
		<script>
			function test()
			{
				StringUtils.toUpperCase();
			}
		</script>
    </head>
    <body>
		<div id="div1" <span id="14_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="14_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?app_id=0&c=news&cf=1001&ch=0&di=128&fv=17&is_app=0&jk=1b73df95847a2cfc&k=style&k0=style&kdi0=0&luki=6&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=fc2c7a8495df731b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D671521%2Ehtml&urlid=0" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" mpid="14" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">style</span></a></span>="width:200px;height:200px;background-color:#465ae0;" οnclick="test();"></div>
     
    </body>
</<span id="15_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="15_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?app_id=0&c=news&cf=1001&ch=0&di=128&fv=17&is_app=0&jk=1b73df95847a2cfc&k=html&k0=html&kdi0=0&luki=3&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=fc2c7a8495df731b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D671521%2Ehtml&urlid=0" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" mpid="15" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">html</span></a></span>>
           

點選div1,可以發現test()函數不會報錯。也就是說,requireJS加載不符合AMD規範的js檔案,跟我們直接在html通過<script>标簽加載,沒有太大的差别。js檔案中引入的全局變量,依然會存在,依然能夠正常使用。

下面我們看下shim參數的使用方式,我們将main.js修改如下:

requirejs.config({
    baseUrl: 'libs',
	shim:{
		dateUtil:{
			  deps:[],
			  exports: 'DateUtils'
		},
		stringUtil:{
			  deps:[],
			  exports: 'StringUtils'
		}
	}
});


require(["dateUtil","stringUtil"], function(dateUtil,stringUtil) {
    
	stringUtil.toUpperCase();
	dateUtil.toString();

});
           

這段代碼可以正常運作,可以看到:shim參數能夠幫助我們以AMD子產品的方式,使用那些不符合AMD規範的子產品。下面接介紹下:deps和exports的含義。exports很好了解,就是子產品的傳回值。main.js中exports的值,一定要與dateUtil.js和stringUtil.js中暴露出的全局變量名稱一緻。很顯然dateUtil.js和stringUtil.js這2個子產品的傳回值,就是暴露出的全局變量window.DateUtils和window.StringUtils,requireJS架構就是将這些全局變量的值傳回,作為子產品的傳回結果。如果dateUtil.js或stringUtil.js中暴露了多個全局變量,那麼exports可以指定其中任何的一個,作為子產品的傳回結果。不過一般的架構,都隻會使用1個全局變量,這樣沖突的可能性會減少,畢竟全局變量越少越好。

上面我們編寫的dateUtil.js和stringUtil.js,都不依賴于其他js子產品,是以指定的deps是空數組。下面我們編寫的aplugin.js和bplugin.js都依賴于子產品util.js。

//aplugin.js
(function(window,util) {
 
	var a = {};
	
	a.toString = function(){
		alert("a="+util.add(1,2));
	};
 
	// 全局變量
	window.a = a;
  
})(window,util);
           
//bplugin.js

var b = {};

b.toString = function(){
	alert("b="+util.add(1,2));
}
           
//util.js
var util = {};

util.add = function(v1,v2){
	return v1+v2;
};
           

main.js代碼如下,隻有設定正确的依賴順序,使用的時候才不會出問題。

requirejs.config({
    baseUrl: 'libs',
	shim:{
		dateUtil:{
			  deps:[],
			  exports: 'DateUtils'
		},
		stringUtil:{
			  deps:[],
			  exports: 'StringUtils'
		},
		aplugin:{
			  deps:["util"],
			  exports: 'a'
		},
		bplugin:{
			  deps:["util"],
			  exports: 'b'
		}
	}
});


require(["stringUtil","dateUtil","aplugin","bplugin"], function(string,date) {
    
	//string.toString();
	//date.toString();
	var aPl = require("aplugin");
	var bPl = require("bplugin");
	aPl.toString();
	bPl.toString();

});
           

很顯然util.js也不符合AMD規範,如果A子產品依賴于B子產品,A子產品不符合AMD規範(使用的是全局變量),那麼B子產品也必須是使用全局變量,否則會報錯。即如果将util.js改成符合AMD規範的寫法,那麼aplugin.js和bplugin.js都會因找不到util對象而報錯。

// 符合AMD規範的util.js

define(function(){
	
	function add(v1,v2)
	{
		return v1+v2;
	}
	
	return {"add":add};

});
           

最後我們看下shim配置參數中init的作用。init可以指定一個函數主要就是用來避免類庫之間的沖突。由于不符合AMD規範的js檔案,會使用全局變量。是以當加載多個子產品的時候存在名字沖突的可能。比如JQuery、UnderScore等架構都會提供一個noConflict()函數來避免名字沖突,noConflict()的實作原理可以參考這篇文章。

我們編寫一個不符合AMD規範的子產品conflict.js,使用了全局變量$E,并提供noConflict方法。

(function(window) {
	// 儲存之前資料
	var _$E = window.$E;

	var myplugin = {"name":"aty"};
	myplugin.noConflict = function(){
		window.$E = _$E;
		return myplugin;
	};
	
	// 向全局對象注冊$E
	window.$E = myplugin;
})(window);
           

将index.html修改如下,在requireJS加載之前,先定義一個全局變量$E。

<!doctype <span id="4_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="4_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?app_id=0&c=news&cf=1001&ch=0&di=128&fv=17&is_app=0&jk=1b73df95847a2cfc&k=html&k0=html&kdi0=0&luki=3&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=fc2c7a8495df731b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D671521%2Ehtml&urlid=0" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" mpid="4" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">html</span></a></span>>
<html>
    <<span id="5_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="5_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?app_id=0&c=news&cf=1001&ch=0&di=128&fv=17&is_app=0&jk=1b73df95847a2cfc&k=head&k0=head&kdi0=0&luki=7&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=fc2c7a8495df731b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D671521%2Ehtml&urlid=0" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" mpid="5" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">head</span></a></span>>
        <title>shim</title>
        <meta charset="utf-8">
		<script>
			var $E = "before";
		</script>
        <script data-main="main.js" <span id="6_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="6_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?app_id=0&c=news&cf=1001&ch=0&di=128&fv=17&is_app=0&jk=1b73df95847a2cfc&k=src&k0=src&kdi0=0&luki=5&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=fc2c7a8495df731b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D671521%2Ehtml&urlid=0" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" mpid="6" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">src</span></a></span>="./../requirejs-2.1.15.js"></script>
    </head>
    <body>
		<div id="div1" <span id="7_nwp" style="padding: 0px; width: auto; height: auto; float: none;"><a target=_blank id="7_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?app_id=0&c=news&cf=1001&ch=0&di=128&fv=17&is_app=0&jk=1b73df95847a2cfc&k=style&k0=style&kdi0=0&luki=6&n=10&p=baidu&q=65035100_cpr&rb=0&rs=1&seller_id=1&sid=fc2c7a8495df731b&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1836545&u=http%3A%2F%2Fwww%2Ebubuko%2Ecom%2Finfodetail%2D671521%2Ehtml&urlid=0" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" mpid="7" style="padding: 0px; color: rgb(51, 51, 51); text-decoration: none;"><span style="padding: 0px; color: rgb(0, 0, 255); width: auto; height: auto;">style</span></a></span>="width:200px;height:200px;background-color:#465ae0;" οnclick="test();"></div>
    </body>
</html>
           

main.js中代碼如下:

requirejs.config({
    baseUrl: 'libs',
	shim:{
		conflict:{
			  deps:[],
			  exports: '$E',
			  init:function(){
				 return $E.noConflict();
			  }
		}
	}
});


require(["conflict"], function(mayConflict) {
    
	alert(mayConflict.name);
	
	alert(window.$E);//before
	
});
           

運作index.html,可以發現conflict.js能夠與之前定義的全局變量$E共存,避免了沖突,這就是通過init實作的。如果沒有定義init,可以看到alert(window.$E)列印的值是undefined。

繼續閱讀