【发布时间】:2021-05-28 02:34:54
【问题描述】:
用例:这允许区分用户是使用基于承诺的样式还是回调样式,因此我可以避免双重计算。我使用 ES6 Proxy 对函数和完成的 setter 进行猴子修补,现在我在两者中都进行了昂贵的计算。我想避免这种情况。无法知道网站使用的是基于 Promise 的版本还是回调版本,因为当网站调用基于 Promise 的版本时,on-completed setter 为空。
相关的原生函数过去没有基于 promise 的版本。
我无法使用静态分析,因为我在修补网站使用的原生函数(其代码不受我控制)
// 2009
// The function is void in 2009
// Today it can return a promise with a value but websites still can use
// 'nativeFooOnCompleted' to get result
nativeFooStart();
nativeFooOnCompleted = function() {};
// Today
// "nativeFooStart" is still required and without that on-completed
// event won't fire
let result = await nativeFooStart();
// or
nativeFooStart();
nativeFooOnCompleted = function() {};
我需要优化运行时。否则,我的现实生活中的函数将在函数内部进行复杂昂贵的计算,无论是否丢弃。 这是 V8 引擎无法处理的事情。我正在修改本机函数(猴子补丁),甚至不是我自己的函数。 在我看来,这是一个简单的问题,因为浏览器 API 允许直接访问脚本的源代码,这样人们就可以遍历代码并确定函数返回值是否被丢弃。
这是突出显示两个函数调用的代码,一个调用者丢弃了返回值,而另一个调用者没有。
function foo() {
return "bar";
}
foo(); // I need to detect this
let bar = foo();
我需要在运行时检测到这一点。根据我的研究,我发现 Perl 有 wantarray,它不仅会告诉您是否分配了返回值。
其他语言只能在编译时完成。
自从创建问题以来,我已经取得了重大进展。我已经能够提出一种方法并且它是有效的,但是它缺少一个可以考虑作为真正解决方案的东西。
function foo() {
// Increase Stacktrace Limit
Error.stackTraceLimit = Infinity;
// Get the stack trace
let stackTrace = (new Error()).stack.split("\n");
// Get the Last Item of Trace and Trim it
let lastLine = stackTrace.pop().trim();
// Get Index of "at "
let index = lastLine.indexOf("at ");
// Get Normalized Line
let normalizedLine = lastLine.slice(index + 2, lastLine.length).trim();
// Regex Pattern to extract line number
let lineNumberPatternRegex = new RegExp(/:(\d+):(?:\d+)[^\d]*$/);
// Get Line Number
let lineNumber = lineNumberPatternRegex.exec(normalizedLine)[1];
// Get the Source Code
let sourceCode = document.currentScript.text.split("\n");
// Store Caller Line Here
let callerLine;
// Test whether we have to count HTML lines
// See, https://stackoverflow.com/q/66388806/14659574
if(sourceCode.length < lineNumber) {
// Get HTML Source Code as String
let HTML = new XMLSerializer().serializeToString(document)
// Get HTML Source Code as Lines
let HTMLSourceLines = HTML.split("\n");
// This part is stuck because Devtools see diff HTML
// I still yet to figure how to grab that
// See, https://stackoverflow.com/q/66390056/14659574
} else {
callerLine = sourceCode[lineNumber - 1];
}
// Detect Variable and Object Assignments
// Minified cases not yet handled here
if(callerLine.includes("=") || callerLine.includes(":")) {
console.log("Not Discarded")
} else {
console.log("Discarded")
}
return "bar"
}
foo();
用户@poke 在这里回答了这个问题的子问题Link for Sub Problem
据他说,
serializeToString(document)将序列化当前文档状态, 包括可能在运行时应用的所有更改。在 在这种情况下,页面添加后添加了其他样式 渲染,但也可能有更剧烈的变化 删除或重新排序。当您从 JavaScript 查看堆栈跟踪时,浏览器的 JavaScript 引擎将尝试为您提供密切相关的信息 与原始源相关,因为那是您的代码的来源 从。如果您使用带有缩小代码的源映射,则浏览器是 通常甚至可以告诉你某件特定的东西是从哪里来的 原始未缩小的代码,即使该代码甚至不紧密 匹配正在执行的代码(例如,使用转译器时)。
最后,你无法真正弄清楚浏览器会告诉你什么 您只需查看文档即可查看代码行的来源 在运行时。如果您的代码遵循非常严格的规则,您可以 通过一些计算来估计这一点,但这不是一种安全的方法。
【问题讨论】:
-
评论不用于扩展讨论;这个对话是moved to chat。
标签: javascript