大きなコールスタックをテストしたい。具体的には、コールスタックの長さが1000に達したときにコンソール警告が必要です。これは通常、何かばかげたことを意味し、微妙なバグにつながる可能性があります。JavaScript内のコールスタックサイズ
JavaScript内で呼び出しスタックの長さを計算することはできますか?
大きなコールスタックをテストしたい。具体的には、コールスタックの長さが1000に達したときにコンソール警告が必要です。これは通常、何かばかげたことを意味し、微妙なバグにつながる可能性があります。JavaScript内のコールスタックサイズ
JavaScript内で呼び出しスタックの長さを計算することはできますか?
厳密なモードでarguments.callee
とcaller
が削除されているため、ECMAScript 5 strictモードでは機能しませんが、すべての主要ブラウザで機能する関数です。
function getCallStackSize() {
var count = 0, fn = arguments.callee;
while ((fn = fn.caller)) {
count++;
}
return count;
}
例:ES5厳密モードで
function f() { g(); }
function g() { h(); }
function h() { alert(getCallStackSize()); }
f(); // Alerts 3
UPDATE 2011年11月1日
、no way to navigate the call stackが単に存在します。残りの唯一のオプションは、new Error().stack
によって返された文字列を解析することです。これは標準ではなく、普遍的にはサポートされておらず、明らかに問題があります。さらにmay not be possible for everです。
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;
}
+1いいねえ。この問題が発生した場合は、Chromeの開発ツールで「6」と警告しますが、これは、コンソールを使用しているときにバックグラウンドで実行されている他の3つの機能があるためです。 – pimvdb
いいですね!だから、ES5の厳格なモードでは、彼らはコールスタックがあまりにも危険だと決めましたか?おそらく、これはコールスタックのデフォルト動作の変更を防ぐためだけです。 –
@Fred arguments.caller/arguments.calleeは、関数のインライン化とテールコールの最適化(ES.nextでは必須)を実行するときに楽しくなります。 – gsnedders
あなたは、このモジュールを使用することができます。 のprintStackTraceを呼び出すhttps://github.com/stacktracejs/stacktrace.js
は、あなたがその長さを確認することができ、配列内のスタックトレースを返します。
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();
このアプローチには2つの主要な欠点もちろんあります
(1)まで使用スタック領域を決定することは、潜在的に高価な操作でありますVMが大きなスタックサイズを持ち、
(2)報告された数値は必ずしも再帰回数ではなく、実際に使用された領域の測定値です(もちろん、これは利点になるかもしれません)。私は上記のstackSizeExplorer
関数の2000再帰として再帰的にスタック上の同じスペースを使用する関数を含む自動生成コードを見てきました。
注:上記のコードはnode.jsでのみテストされています。しかし、私はそれが静的なスタックサイズを使用するすべてのVMで動作すると仮定します。
[this](http://eriwen.com/javascript/js-stack-trace/)は役に立ちますか? –
コードDave Newtonは、例外をスローするように指示し、ブラウザに基づいてそのプロパティを調べ、 'e'としてキャッチし、そのプロパティを調べます。 ChromeとMozillaでは、 'e.stack'を使用し、Opera 10+は' e.stacktrace'を使用し、他の人は 'e.message'プロパティを理解しようとします。 –
エラースタックトレースでは最大10個のスタックエントリしか使用できませんか? http://jsfiddle.net/pimvdb/AuyP7/ – pimvdb