近一个月里和同事一块儿将刚接手系统从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 });