当我在 Node JS 中调用 modernizr.build 时非常不寻常的作用域行为
Very unusual scope behaviour when I call modernizr.build in Node JS
我正在尝试同时使用 Modernizr 构建多个 json,但它似乎超出了我的功能范围。
很难解释所以看看这个例子,如果你不相信我,试试看:
[1,2,3,4,5].forEach(function(i){
require("modernizr").build({}, function (result) {
console.log(i);
});
})
输出:
5
5
5
5
5
而不是预期的 1、2、3、4、5,就像任何类似的函数一样。
在我使用类似 ECMAScript 的语言编写代码的所有年中,我以前从未遇到过这种行为,并且围绕这样的想法构建了我的项目(和以前的项目),即你不能像那样破坏函数的范围。
它会破坏任何基于承诺甚至简单回调的系统。
这让我困惑了一整天,我找不到合适的解决办法。
我什至很难概念化导致这种情况发生的原因。
请帮忙。
编辑:
好的,看来你们都被 forEach 挂断了……
这是另一个示例,可以使它更清楚一点:
function asd(i){
require("modernizr").build({}, function (result) {
console.log(i);
});
}
asd(1);
asd(2);
asd(3);
asd(4);
产出
4
4
4
4
到底发生了什么事?
功能块是异步调用的,所以这种行为是预料之中的,因为这个调用比你的 foreach 慢得多,所以当你到达 function (result) {}
块时 i
已经五
与此处 Node.JS: How to pass variables to asynchronous callbacks? 中描述的问题完全相同,您应该能够使用相同的解决方案
[1,2,3,4,5].forEach(function(i){
(function(i) {
require("modernizr").build({}, function (result) {
console.log(i);
});
})(i);
})
未经测试,但类似的东西应该可以工作
Modernizr 特有的问题与全局变量被破坏有关。
build
命令基本上是一个大型 requirejs
配置函数,全部由大型配置对象提供支持。在函数的顶部建立了一些基本的东西,它们总是正确的
{
optimize: 'none',
generateSourceMaps: false,
optimizeCss: 'none',
useStrict: true,
include: ['modernizr-init'],
fileExclusionRegExp: /^(.git|node_modules|modulizr|media|test)$/,
wrap: {
start: '\n;(function(window, document, undefined){',
end: '})(window, document);'
}
}
然后,由于 Modernizr 可以在浏览器和节点中工作而无需更改,因此需要有一种方法让它知道它是否应该通过文件系统或通过 http 加载其依赖项。所以我们在环境检查中添加了更多选项,例如 basePath
if (inBrowser) {
baseRequireConfig.baseUrl = '/i/js/modernizr-git/src';
} else {
baseRequireConfig.baseUrl = __dirname + '/../src';
}
此时,配置对象被传递到 requirejs.config
,它连接了 require 并允许我们开始调用 build
。
最后,在创建所有这些之后,我们有一个构建函数,它最终还会再次修改配置对象以进行构建特定设置(构建中的实际检测,正则表达式去除一些 AMD crud,等)。
所以这是最终发生的事情的超级简化伪代码版本
var config = {
name: 'modernizr'
}
if (inBrowser) {
config.env = 'browser';
} else {
config.env = 'node';
}
requirejs.config(config);
module.exports = function(config, callback) {
config.out = function (output) {
//code to strip out AMD ceremony, add classPrefix, version, etc
callback(output)
}
requirejs.optimize(config)
}
发现问题了吗?
因为我们在 运行 之前接触了配置对象的 .out
方法(其范围是整个模块,因此它的上下文保存在 build()
调用之间)异步 require.optimize 函数,每次调用 build
时,您传递的回调都会重写 .out
方法。
这应该会在几个小时内在 Modernizr 中得到修复
我正在尝试同时使用 Modernizr 构建多个 json,但它似乎超出了我的功能范围。 很难解释所以看看这个例子,如果你不相信我,试试看:
[1,2,3,4,5].forEach(function(i){
require("modernizr").build({}, function (result) {
console.log(i);
});
})
输出:
5
5
5
5
5
而不是预期的 1、2、3、4、5,就像任何类似的函数一样。
在我使用类似 ECMAScript 的语言编写代码的所有年中,我以前从未遇到过这种行为,并且围绕这样的想法构建了我的项目(和以前的项目),即你不能像那样破坏函数的范围。
它会破坏任何基于承诺甚至简单回调的系统。 这让我困惑了一整天,我找不到合适的解决办法。 我什至很难概念化导致这种情况发生的原因。 请帮忙。
编辑:
好的,看来你们都被 forEach 挂断了…… 这是另一个示例,可以使它更清楚一点:
function asd(i){
require("modernizr").build({}, function (result) {
console.log(i);
});
}
asd(1);
asd(2);
asd(3);
asd(4);
产出
4
4
4
4
到底发生了什么事?
功能块是异步调用的,所以这种行为是预料之中的,因为这个调用比你的 foreach 慢得多,所以当你到达 function (result) {}
块时 i
已经五
与此处 Node.JS: How to pass variables to asynchronous callbacks? 中描述的问题完全相同,您应该能够使用相同的解决方案
[1,2,3,4,5].forEach(function(i){
(function(i) {
require("modernizr").build({}, function (result) {
console.log(i);
});
})(i);
})
未经测试,但类似的东西应该可以工作
Modernizr 特有的问题与全局变量被破坏有关。
build
命令基本上是一个大型 requirejs
配置函数,全部由大型配置对象提供支持。在函数的顶部建立了一些基本的东西,它们总是正确的
{
optimize: 'none',
generateSourceMaps: false,
optimizeCss: 'none',
useStrict: true,
include: ['modernizr-init'],
fileExclusionRegExp: /^(.git|node_modules|modulizr|media|test)$/,
wrap: {
start: '\n;(function(window, document, undefined){',
end: '})(window, document);'
}
}
然后,由于 Modernizr 可以在浏览器和节点中工作而无需更改,因此需要有一种方法让它知道它是否应该通过文件系统或通过 http 加载其依赖项。所以我们在环境检查中添加了更多选项,例如 basePath
if (inBrowser) {
baseRequireConfig.baseUrl = '/i/js/modernizr-git/src';
} else {
baseRequireConfig.baseUrl = __dirname + '/../src';
}
此时,配置对象被传递到 requirejs.config
,它连接了 require 并允许我们开始调用 build
。
最后,在创建所有这些之后,我们有一个构建函数,它最终还会再次修改配置对象以进行构建特定设置(构建中的实际检测,正则表达式去除一些 AMD crud,等)。
所以这是最终发生的事情的超级简化伪代码版本
var config = {
name: 'modernizr'
}
if (inBrowser) {
config.env = 'browser';
} else {
config.env = 'node';
}
requirejs.config(config);
module.exports = function(config, callback) {
config.out = function (output) {
//code to strip out AMD ceremony, add classPrefix, version, etc
callback(output)
}
requirejs.optimize(config)
}
发现问题了吗?
因为我们在 运行 之前接触了配置对象的 .out
方法(其范围是整个模块,因此它的上下文保存在 build()
调用之间)异步 require.optimize 函数,每次调用 build
时,您传递的回调都会重写 .out
方法。
这应该会在几个小时内在 Modernizr 中得到修复