JavaScript中的调用栈大小
Call stack size within JavaScript
我想测试大型调用堆栈。具体来说,我希望在调用堆栈长度达到1000时发出控制台警告。这通常意味着我做了一些愚蠢的事情,并可能导致微妙的错误。
我可以在JavaScript中计算调用堆栈长度吗?
这是一个可以在所有主流浏览器中工作的函数,尽管它不能在ECMAScript 5严格模式下工作,因为arguments.callee
和caller
已经在严格模式下被删除了。
function getCallStackSize() {
var count = 0, fn = arguments.callee;
while ( (fn = fn.caller) ) {
count++;
}
return count;
}
的例子:
function f() { g(); }
function g() { h(); }
function h() { alert(getCallStackSize()); }
f(); // Alerts 3
UPDATE 1 November 2011
在ES5严格模式下,根本没有办法导航调用堆栈。剩下的唯一选择是解析new Error().stack
返回的字符串,这是非标准的,不是普遍支持的,显然有问题,甚至这可能永远不可能。
UPDATE 2013年8月13日
此方法还受到以下事实的限制:在单个调用堆栈中多次调用的函数(例如通过递归)将使getCallStackSize()
进入无限循环(如评论中的@Randomblue所指出的)。getCallStackSize()
的改进版本如下:它跟踪之前看到的函数,以避免进入无限循环。但是,返回值是在遇到重复之前调用堆栈中不同函数对象的数量,而不是完整调用堆栈的真实大小。不幸的是,这是你能做的最好的了。
var arrayContains = Array.prototype.indexOf ?
function(arr, val) {
return arr.indexOf(val) > -1;
} :
function(arr, val) {
for (var i = 0, len = arr.length; i < len; ++i) {
if (arr[i] === val) {
return true;
}
}
return false;
};
function getCallStackSize() {
var count = 0, fn = arguments.callee, functionsSeen = [fn];
while ( (fn = fn.caller) && !arrayContains(functionsSeen, fn) ) {
functionsSeen.push(fn);
count++;
}
return count;
}
你可以使用这个模块:https://github.com/stacktracejs/stacktrace.js
调用printStackTrace返回数组内的堆栈跟踪,然后您可以检查其长度:
var trace = printStackTrace();
console.log(trace.length());
另一种方法是在顶层堆栈帧中测量堆栈上的可用大小,然后通过观察可用空间减少了多少来确定堆栈上已使用的空间。在代码:
function getRemainingStackSize()
{
var i = 0;
function stackSizeExplorer() {
i++;
stackSizeExplorer();
}
try {
stackSizeExplorer();
} catch (e) {
return i;
}
}
var baselineRemStackSize = getRemainingStackSize();
var largestSeenStackSize = 0;
function getStackSize()
{
var sz = baselineRemStackSize - getRemainingStackSize();
if (largestSeenStackSize < sz)
largestSeenStackSize = sz;
return sz;
}
例如:function ackermann(m, n)
{
if (m == 0) {
console.log("Stack Size: " + getStackSize());
return n + 1;
}
if (n == 0)
return ackermann(m - 1, 1);
return ackermann(m - 1, ackermann(m, n-1));
}
function main()
{
var m, n;
for (var m = 0; m < 4; m++)
for (var n = 0; n < 5; n++)
console.log("A(" + m + ", " + n + ") = " + ackermann(m, n));
console.log("Deepest recursion: " + largestSeenStackSize + " (" +
(baselineRemStackSize-largestSeenStackSize) + " left)");
}
main();
当然,这种方法有两个主要的缺点:
(1)当VM具有较大的堆栈大小和
时,确定已用完的堆栈空间可能是一个昂贵的操作。(2)报告的数字不一定是递归的数量,而是堆栈上使用的实际空间的度量(当然,这也可能是一个优势)。我见过自动生成的代码,其中包含的函数每次递归在堆栈上使用与上述stackSizeExplorer
函数的2000次递归相同的空间。
注意:我只测试了上面的代码与node.js。但我认为它将适用于所有使用静态堆栈大小的vm。
- 我需要从php调用javascript或jquery
- 如何在webView,Android中从@JavascriptInterface方法调用Javascript
- 使用html表单中的参数调用JavaScript函数
- 可以´t调用JavaScript中的函数
- 在按钮上调用Javascript函数
- 如何从Objective-C代码中调用javascript代码
- 当库在页脚中加载时,基于PHP条件调用Javascript
- 可以't在Jasmine中调用Javascript函数
- 在page_load事件上调用javascript函数
- 如何在ajax中调用javascript对象的方法
- 如何使用WPF调用JavaScript对象的函数
- 我们可以用参数对象集合而不是原始数据来调用JavaScript collection.reduce()方法吗
- 在新的浏览器选项卡上加载新的aspx页面后调用JavaScript函数
- 从附加文本调用javascript(订单车)
- 在线程循环中调用JavaScript
- 在指定时间后多次调用Javascript中的函数
- 未调用Javascript onscroll事件
- 如何正确调用Javascript中的匿名函数
- 从字符串调用javascript函数
- 无法从活动调用 javascript 函数