提问者:小点点

有没有访问/修改节点模块/函数执行上下文的方法


我理解了Node/Javascript的作用域规则,并且,例如,通过理解Javascript中的执行上下文和执行堆栈,我认为我理解了执行上下文如何工作的原理:问题是您能够实际访问它们吗?

对于2015年的问题How can I get the execution context of a javascript function inside V8 engine(涉及(ab)using

(我很清楚这可能是XY问题,也可能是滥用Node/JavaScript的愿望:希望下面的背景部分能提供更多的上下文,如果有一种不同的方式来实现我想要的目标,那也能奏效。)

简单地说,我想实现像这样的事情:

sharedVar = 1 ;
anotherModule.someFunction() ;
console.log( sharedVar ) ;     // Where 'sharedVar' has changed value

在另一个模块中有一个函数可以随意改变其调用方作用域中的变量,这似乎是“危险的事情”的定义,所以如果有可能的话,我希望它应该更像:

sharedVar = 1 ;
anotherModule.hereIsMyExecutionContext( SOMETHING ) ;
anotherModule.someFunction() ;
console.log( sharedVar ) ;     // Where 'sharedVar' has changed value

应该类似于:

let otherExecutionContext ;
function hereIsMyExecutionContext( anExecutionContext ) {
    otherExecutionContext = anExecutionContext ;
}
function someFunction() {
    //do something else
    otherExecutionContext.sharedVar = 42 ;
}

问题变成了我可以用什么(如果有的话)替换

>

从函数返回一个新值。在我的实际用例中,我希望能够更改几个变量。必须执行既不方便又分散注意力(虽然函数可能会更改这些变量中的一些值,但这不是函数的主要目的)。

具有的变量成员。虽然使用将是一种干净,封装的方式,但我真的希望不必每次都使用模块名:它不仅可以更多地键入,而且会分散使用这些变量的代码的注意力。

使用全局范围。如果我没有使用,则可以在全局对象上使用,并且两个代码位都可以自由访问。由于我使用的是strict-mode(并且不想改变它),我需要使用,这与将它附加到具有相同的“累赘”。

请使用。看起来像是从一个OtherModule/code>中使用,使用共享变量的模块必须是ES模块(而不是CommonJS模块),并且不能使用动态加载(我也需要它)。以ESM方式动态加载它(使用作为返回承诺的函数)似乎可以工作,但重复加载来自缓存。根据这个关于如何用ES6导入重新导入模块的答案,没有一种“干净”的方式来清除缓存(参见用于CommonJS模块的)。如果有一种简单的方法可以使通过加载的缓存ESM无效,请随时为这个问题添加一个答案(请在这里添加一个注释),尽管ESM上的当前节点JS文档没有提到一个,所以我不抱希望:-(

12月初,SO网站上的一个随机问题提醒了我Code网站的出现,那里每天都有不同的编程问题出现,于是我决定尝试使用Node。我使用独立的JS文件解决了前两个问题,这时我意识到在每个文件之间复制粘贴了许多公共代码。在解决这些难题的同时,我决定创建一个“框架”程序来协调它们,并提供尽可能多的通用代码。创建框架的一个目标是单个“解决方案”文件应该尽可能“精简”:它们应该包含解决问题所需的绝对最少的代码。

与此问题相关的框架的一个特性是,它每次都会重新加载(当前使用)选定的解决方案文件,这样我就可以在不重新运行框架的情况下处理解决方案。这就是为什么切换到和ES模块会有缺点,因为我无法(干净地)使缓存的解决方案模块无效。

另一个相关特性是框架提供了函数。这些格式化并打印它们的参数:第一个总是;第二种是有条件的,取决于解决方案是正常运行还是在“跟踪”模式下运行。后者只不过是:

function trace( ... ) {
    if( traceMode ) {
        print( ... )
    }
}

每个问题都有两组输入:一个“示例”输入(为其提供预期答案)和“实际”输入(往往更大,涉及更多)。框架通常会在启用跟踪的情况下运行示例输入(这样我就可以检查“内部工作”),在禁用跟踪的情况下运行“实际”输入(因为它会产生太多的输出)。对于大多数问题来说,这是很好的:为调用准备参数,然后调用却发现没有什么可做,而“浪费”的时间是可以忽略不计的。然而,对于一个特定的解决方案(涉及1000万次迭代),差异是显著的:在做忽略的跟踪时接近30s;如果它们的调用被commented-out,或者我通过使用以下构造“短路”trace-mode决策:

TRACE && aoc.print( ... )

其中根据需要设置为true/false。我的“问题”是不能跟踪框架中的跟踪模式:我必须手动设置它。当然,我可以使用,但是正如上面所讨论的,这比我所希望的要多得多,并且使解决方案的代码比我理想中想要的更“杂乱”(我坦率地承认这些都是一些微不足道的原因。。。)


共1个答案

匿名用户

与此问题相关的框架的一个特性是,它每次都会重新加载选定的解决方案文件

这是关键。您不应该将加载,解析和执行留给,因为您无法控制它。相反,将文件作为文本加载,对代码做一些邪恶的事情,然后

可以使用模块或通过扰乱模块系统来完成计算。

我所提到的邪恶的事情最容易就是在代码前加一些“隐式导入”,不管是还是仅仅。但是您也可以执行任何其他类型的预处理,例如宏替换,在这里您可能只需删除包含的行。