近一個月裏和同事一塊兒將剛接手系統從sea.js切換到require.js。一方面感受requirej比seajs更容易作工程化,一方面sea.js目前不更新了,而require社區仍然比較活躍。沒有直接上vue或者react之類新潮的框架,是考慮到目前系統功能已經相對穩定了,業務複雜,組件數量不少,傷筋動骨的換框架一方面時間有限,一方面項目沒有作單元測試,風險太大,後面新項目起來的話應該是會直接上react了。sea切換到require的改動相對來講比較固定,能夠徹底不動原有業務代碼,工做量和風險可控。vue
不過我的其實對requirejs自己不太瞭解,期間仍是掉進了幾個坑裏的。先總結下在切換到requirejs中遇到的兩個問題吧。react
1.requirejs不像seajs要求js文件被define、require包裹,能夠直接require一個不符合規範的js數組
module1: (function(){ window.myModule1 = { info:'module1' } })(); module2: (function(){ if(window.myModule1){ console.log(window.myModule1.info); } })(); main: require(['./module1', './module2'], function(){ ... })
以上代碼徹底能夠正常運行,不會報錯。但會發現一個問題,屢次執行的結果會不一致,這是由於module1和module2不是按照require數組參數裏的順序加載的,這種狀況下沒有固定的加載順序。
有兩種處理方式:
若是兩個js都是業務代碼能夠自行維護,就把兩個js都改爲AMD規範緩存
module1: define('module1', function(){ window.myModule1 = { info:'module1' } }); module2: require(['module1'], function(){ console.log(window.myModule1.info); }) main: require(['./module2'], function(){ ... })
若是js是外部插件,儘可能用不改源碼的方式讓兩個js的加載變得有序。須要在require的config.js配置文件中加入一段代碼,讓requirejs知道兩個js之間的依賴關係,保證module2在module1加載後再加載框架
requirejs.config({ paths: { "module1": "./module1", "module2": "./module2" }, shim:{ "module2": ["module1"] } })
2.require返回的對象全局共享一個。異步
module1: define('module1', [], function(){ return { val : 0, init : function(){ return this; }, add : function(num){ this.val += num; } }; }); main: require(['module1'], function(m){ m.init().add(1); console.log(m.val); //1 }); require(['module1'], function(m){ m.init().add(1); console.log(m.val); //2 });
以上例子說明,module1第一次被require之後,返回的對象m會被緩存起來,第二次被require的時候,返回的是以前緩存起來的m。屢次require同一個模塊時,返回的對象其實是同一個。這與seajs是不一樣的,seajs每次異步加載都會返回一個,之前基於seajs寫的代碼裏切換成require之後就會留下潛在的坑。
解決方法簡單粗暴,全部返回對象的地方全換成返回function,執行function返回原對象。requirejs
module1: define('module1', [], function(){ return function(){ return { val : 0, init : function(){ return this; }, add : function(num){ this.val += num; } } }; }); main: require(['module1'], function(m){ m().init().add(1); console.log(m.val); //1 }); require(['module1'], function(m){ m().init().add(1); console.log(m.val); //1 });