假设您有一个网站,该网站使用一些 JavaScript 库,无论是您自己的库还是第三方编写的库。除了最小化和混淆之外,我想知道是否可以通过删除未使用的函数来进一步减小脚本有效负载的大小。一旦达到一定程度的复杂性,就很难/不可能知道哪些函数最终在所有可能的执行路径下被调用。这让我产生了一个问题:是否有任何工具或方法可以确定网页使用一段时间后,哪些用户定义的函数(而不是内置函数)没有被调用?
一种明显的可能性是将所有函数定义包装在对注册函数的调用中,其中 1) 将函数添加到注册器,并且 2) 注入(inject)一些代码以将函数标记为已被调用。然后就可以向函数注册器查询那些尚未被调用的函数。然而,这种方法极其复杂。最好的选择是在 Web 服务器上编写一个 JavaScript 代码解析器,该解析器由运行时标志(“处于 JS 诊断模式”)启用,该解析器捕获所有 JavaScript 响应并相应地修改代码。但不需要太多想象力就可以意识到这将是多么容易出错和困难。
更新:只是澄清一下,我并不是在寻找自动删除未使用功能的解决方案,我对此感到不舒服,因为担心会引入不稳定。相反,函数使用的开发时间分析可以让我选择要删除哪些包含/函数,以便最终的解决方案可以在发布之前进行正确的测试。
最佳答案
Once you reach a certain level of complexity, it becomes difficult/impossible to know which functions end up getting called under all possible execution paths.
“困难/不可能”中不需要斜线。 消除死代码相当于解决停机问题,因此根本不可能,就这样。
are there any tools or any ways to determine, after a period of usage of the web page, what user-defined functions (not built-in ones) have not been called?
这介于分析(确定代码的哪些部分执行频率)和覆盖率分析(确定代码的哪些部分已执行)之间全部)。更准确地说,听起来您正在寻找功能覆盖率。
请注意,代码覆盖率经常在测试上下文中讨论,以至于对于某些人来说,“代码覆盖率”和“测试覆盖率”是同义词,但代码覆盖率与测试无关。它只是指“当我运行特定工作负载时,代码的哪些部分被执行?”的问题。
上述问题中的“部分”一词有不同的解释方式,因此产生了不同类型的覆盖范围:
- 行覆盖率:哪些行被执行?
- 函数覆盖率:哪些函数被执行? (这是您感兴趣的。)
- 语句覆盖率:哪些语句被执行?
- 表达式覆盖率:哪些表达式被执行?
- 分支覆盖:条件的哪些分支被执行?
- 路径覆盖:通过 block 的哪些路径被执行?
行覆盖率通常没有用,因为您只需重新格式化代码即可更改数字。事实上,在 ECMAScript 中,我总是可以通过简单地将所有内容写在一行上来执行所有行。
分支覆盖率和路径覆盖率的区别可以通过这段代码来举例说明:
function foo(bar, baz) {
if (bar) {
console.log("bar");
} else {
console.log("no bar");
}
if (baz) {
console.log("baz");
} else {
console.log("no baz");
}
}
为了覆盖所有分支,我需要两次调用:
foo(true, false);
foo(false, true);
为了覆盖该函数的所有可能路径,我需要四次调用:
foo(true, true);
foo(true, false);
foo(false, true);
foo(false, false);
如果您根据函数覆盖率进行启发式死代码消除,您将能够删除未使用的函数。如果您根据分支覆盖率执行此操作,您甚至可以从 if
或 switch
语句中删除未使用的分支。
如果您正在寻找代码覆盖工具,您可能需要查看测试空间,因为这是它们最常使用的地方。您可能必须编写自己的死代码消除工具,或者修补现有的压缩器,以便它可以从代码覆盖率运行中读取日志文件并据此做出决策。
据我所知,没有现有的工具可以做到这一点,尽管我可能是错的。
关于javascript - 确定哪些 JavaScript 函数未被调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62412819/