我发现了一个特殊的javascript编码组合/序列会导致奇怪的node.js运行时错误(“XXX不是函数”,但我确实将XXX定义为函数!)。它不依赖于任何其他库和工具,但一些简单的打字稿/ javascript代码可能会导致此错误。我无法理解为什么我会遇到这样的运行时错误,任何人都可以帮助我吗?如果它对应于某个node.js已知错误,请告诉我相应的票号,以便我可以了解更多相关信息。感谢〜!
(我已经升级到最新版本:node.js v4.1.1,Visual Studio 2015社区版,VS 2015 node.js工具1.1.30716.01)
事实上,我正在使用Visual Studio 2015社区版来编写一些打字稿代码( .ts),并自动获取VS生成的javascript代码( .js)。针对这种特殊的编码序列,Visual Studio 2015可以愉快接受它,并生成相应的javascript代码。但是当node.js运行那些javascript代码时,node.js会生成奇怪的运行时错误。因此,我认为这种行为只与node.js完全相关,而不是typescript。
总之,VS2015中的typescript模块认为这个组合是一个有效的打字稿/ javascript序列,但是生成的javascript文件无法由node.js执行,如果我改变了一些语句的顺序,它就可以了〜 !真奇怪。
打字稿/ javascript编码组合/序列包含8个简单文件。我花了几天时间来缩小问题,发现组合是最简单的形式,无法进一步简化以获得相同的运行时错误。如果我进一步删除某些部分,运行时错误将消失。执行“main.js”文件时,node.js会生成以下错误,但我无法理解原因。 A_function1()和A_function2()是2个简单函数(你可以看到下面的完整文件内容),node.js可以成功找到并执行A_function1(),但不能找到和执行A_function2()。
c:\>node --version
v4.1.1
c:\>node main.js
c:\c.js:3
a.A_function2();
^
TypeError: a.A_function2 is not a function
at Object.C_function (c:\c.js:3:7)
at Object.<anonymous> (c:\main.js:4:3)
at Module._compile (module.js:434:26)
at Object.Module._extensions..js (module.js:452:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Module.runMain [as _onTimeout] (module.js:475:10)
at Timer.listOnTimeout (timers.js:89:15)
Press any key to continue...
=============================================== ========================== 8个打字稿文件如下:
main.ts
import d = require("./d"); // --> If I change the order of these "imports" to "c --> d --> e", the runtime error would disappear.
import e = require("./e");
import c = require("./c");
c.C_function();
d;
e;
console.log("safe!"); // --> If the execution reaches this line, every thing would be fine. If that runtime error happened, you could not see this "safe!"
a.ts
import g = require("./g");
class A {
static A_function1() {
}
static A_function2() {
var tmp = g.G_enum.G_enum_value_1;
}
}
export = A;
b.ts:
import a = require("./a");
export function B_function() {
a.A_function1(); // --> This line would not cause any runtime error, node.js could successfully find what A_function1() is, and execute it~!
}
c.ts:
import a = require("./a");
export function C_function() {
a.A_function2(); // --> This line causes the runtime error, but A_function2() is really a function~!
}
d.ts:
import f = require("./f");
f.F_function;
e.ts:
import g = require("./g");
g.G_function;
f.ts:
import b = require("./b");
export function F_function() {
b.B_function();
}
g.ts:
import c = require("./c");
export enum G_enum {
G_enum_value_1
}
export function G_function() {
c.C_function();
}
=============================================== ========================== VS2015生成的相应javascript文件如下:
main.js:
var d = require("./d");
var e = require("./e");
var c = require("./c");
c.C_function();
d;
e;
console.log("safe!");
a.js:
var g = require("./g");
var A = (function () {
function A() {
}
A.A_function1 = function () {
};
A.A_function2 = function () {
var tmp = g.G_enum.G_enum_value_1;
};
return A;
})();
module.exports = A;
b.js:
var a = require("./a");
function B_function() {
a.A_function1();
}
exports.B_function = B_function;
c.js:
var a = require("./a");
function C_function() {
a.A_function2();
}
exports.C_function = C_function;
d.js:
var f = require("./f");
f.F_function;
e.js:
var g = require("./g");
g.G_function;
f.js:
var b = require("./b");
function F_function() {
b.B_function();
}
exports.F_function = F_function;
g.js:
var c = require("./c");
(function (G_enum) {
G_enum[G_enum["G_enum_value_1"] = 0] = "G_enum_value_1";
})(exports.G_enum || (exports.G_enum = {}));
var G_enum = exports.G_enum;
function G_function() {
c.C_function();
}
exports.G_function = G_function;
答案 0 :(得分:3)
basarat的答案是正确的,因为你有一个循环引用,但你的问题答案并不完全(尽管,公平地说,你所询问的事实上并不是很特别;循环模块依赖性是公平的在某些代码结构中很常见。)
在您的代码中,模块a
的导出方式与其他模块的导出方式不同。在模块a
中,导出模块的不同值(export = A
),而其他模块只是将函数添加到其默认导出对象(export function C_function
)。模块a
尝试导出不同值的事实是问题的关键。
当Node.js中出现循环模块依赖关系时,为了打破循环,Node.js必须将冲突模块的导出值定义为 it 创建的默认导出对象,甚至如果您尝试指定显式导出值。对于只是将属性添加到默认导出对象(export function
和export var
)的模块,这不是问题。但是,当您尝试定义不同的导出对象(使用export =
)时,该对象将最终被丢弃,以支持默认导出对象。
换句话说,代码中会忽略export = A
,因为该模块最终会成为这样一个循环的一部分:
主要 - &gt; d - &gt; f - &gt; b - &gt; a - &gt; g - &gt; c - &gt;的一强>
第二次看到a
时,运行时别无选择,只能给c
一个默认的导出对象,否则它无法解析依赖图。
要修复您的调用,您需要重新构建代码以删除循环依赖项,或者需要导出附加到默认导出对象的函数和变量,而不是尝试导出您创建的其他对象你自己(class A
)。
答案 1 :(得分:2)
如果您有循环引用:https://nodejs.org/api/modules.html#modules_cycles,可能会返回一个对象,该对象现在可能没有与模块导入关联的功能。
给https://github.com/TypeStrong/atom-typescript#dependency-view一个去,它会找到你可能有的任何循环引用