{ Hello Magento 2 }

解决 Magento 2 应用问题,更注重深度挖掘。(ง •̀_•́)ง

0%

RequireJS 的 shim 用法

综述

RequireJS 遵循 AMD 规范(异步模块定义)。理论上来说,RequireJS 加载的模块必须符合 AMD 规范,使用 define() 函数定义。但是,由于历史原因,大量的 js 库并不符合规范。这样加载非规范的模块,就需要用到 shim 比如 underscore 和 backbone 都不符合 AMD 规范,如果要加载他们,就要像这样使用:

1
2
3
4
5
6
7
8
9
10
11
require.config({
    shim: {
      'underscore':{
        exports: '_'
      },
      'backbone': {
        deps: ['underscore', 'jquery'],
        exports: 'Backbone'
      }
    }
  });

exports 是模块的返回值,该值一定要与库暴露的全局变量名称一致。 deps 表明模块的依赖,如果 A 模块依赖于 B 模块,而 A 模块不符合 AMD 规范,使用全局变量,那么 B 模块也必须使用全局变量,不然 A 模块会找不到 B 模块的依赖对象而报错。

准备

下面开始做实验。 File: test.html

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html>
<head>
<title>shim</title>
<script src="https://cdn.bootcss.com/require.js/2.3.5/require.min.js" data-main="main.js"></script>
</head>
<body>

</body>
</html>

File: a.js

1
2
3
4
5
6
7
8
9
// 立即执行函数,不暴露私有成员
(function(window){
var a = {};
a.sayHello = function(){
alert("Hello this is A");
return 'Hello';
}
window.a = a;
})(window)

File: main.js

1
2
3
require(['a'],function(a) {
console.log(a);
});

载入文档,在 console 中我们会看到,输出 undefined a is not defined 但是我们查看浏览器的 element 和 network 会发现,实际上 a.js 已经被加载进来了。 a.js has been loaded a.js has been loaded network 下面我们在 console 中输入:

1
a.sayHello();

console 中输入命令 可以看出实际上 a.js 中暴露的全局变量还是存在的。

使用 shim

下面我们用 shim 让 RequireJS 可以获得暴露的全局变量作为返回值。 修改 main.js

1
2
3
4
5
6
7
8
9
10
11
requirejs.config({
shim: {
a:{
deps:[],
exports: 'a'
}
}
});
require(['a'],function(a) {
console.log(a);
});

然后刷新文档,这次肯定是输出内容了。 exports 有效 如果我们把 exports: 'a' 改成 exports: 'something' 那么再刷新,一定会发现又输出 undefined 所以,exports 是模块的返回值,该值一定要与库暴露的全局变量名称一致。

使用 deps

下面来实验 deps 的用法,假设 a.js 依赖于 b.js

正确的写法

File: b.js

1
2
3
4
5
6
7
8
9
10
11
var b = {};

console.log('b');

b.string = 'Hello, this is a string from b.js';
b.getString = function() {
return this.string;
}
b.setString = function(string) {
this.string = string;
}

File: a.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 立即执行函数,不暴露私有成员
(function(window){
console.log('a');

var a = {};
a.sayHello = function(){
alert("Hello this is A");
return 'Hello';
}
a.getBString = function() {
alert(b.getString());
}
window.a = a;
})(window)

File:main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
requirejs.config({
shim: {
a:{
deps:['b'],
exports: 'a'
},
b: {
deps:[],
exports: 'b'
}
}
});
require(['a'],function(aAlias) {

aAlias.getBString();

});

效果如下: depes 用法效果 这是标准的写法,下面我们来实验一个不好的写法。

错误的写法

将 main.js 改成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
requirejs.config({
shim: {
a:{
deps:[],
exports: 'a'
},
b: {
deps:[],
exports: 'b'
}
}
});
require(['a','b'],function(aAlias, bAlias) {

aAlias.getBString();

});

我们并没有声明 a.js 依赖 b.js 而是在使用的时候将 b.js require 进来了。这样在本例中也是正常的。但仅仅是因为本例太简单,对执行的先后顺序没有要求而已,换个场景可能就失效了。 require(['a','b'],function(aAlias, bAlias) 仅仅表示 a b 都加载完成后,执行回调函数,但是 加载的顺序是不固定的。执行的顺序是固定的,按照依赖声明的先后顺序执行。 在上面我们埋了 console.log('a)console.log('b') 那么在不好的写法中,控制台中打印的顺序是不固定的,有时候是 a b 有时候是 b a ,而正确的例子中,指定顺序是固定的,一定是 b a 下面是错误的写法,多次刷新的结果,可以看出,顺序是有变化的。 执行顺序不一定

参考文档

使用requireJS加载不符合AMD规范的js文件:shim的使用方式和实现原理 Javascript模块化编程(二):AMD规范