2

近一个月里和同事一起将刚接手系统从sea.js切换到require.js。一方面感觉requirej比seajs更容易做工程化,一方面sea.js目前不更新了,而require社区仍然比较活跃。没有直接上vue或者react之类新潮的框架,是考虑到目前系统功能已经相对稳定了,业务复杂,组件数量很多,伤筋动骨的换框架一方面时间有限,一方面项目没有做单元测试,风险太大,后面新项目起来的话应该是会直接上react了。sea切换到require的改动相对来说比较固定,可以完全不动原有业务代码,工作量和风险可控。

不过个人其实对requirejs本身不太了解,期间还是掉进了几个坑里的。先总结下在切换到requirejs中遇到的两个问题吧。

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返回原对象。

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
    });

梦梦她爹
1.8k 声望122 粉丝

引用和评论

0 条评论