[トリビアの種] TaskQueueはオーバーフローするのか?結果は…ォアフン


この記事は、私が素朴な疑問を抱いたところから検証してみたまでの一部始終です。
勘違い等がありましたら、ご指摘いただけますと幸いです。

結果だけを知りたい方はこちら。

エラーは発生しなかった。

今回のお便りはこちら

ある日、JavaScriptの非同期処理について勉強していた時にスタックとキューの存在を知りました。1
これが「スタックにタスクが積まれすぎてオーバーフローになるのか!」と膝を打ちました。
それと同時に、キューオーバーフローって聞いたことないなと疑問に思いました。
そこで、キューオーバーフローになるようにあえてコードを実行するとどうなるのでしょうか?
これって種になりませんか?よろしくお願いします。

このトリビアの種つまりこういうことになります

キューオーバーフローになるようにあえてコードを実行すると結果は、、、「ォアフン」。

スタックオーバーフローとは

wikipedia先生お願いします。

スタックオーバーフロー (英: stack overflow) は、コンピュータプログラムにおいて、コールスタック領域の限界を超えたデータプッシュにより発生する、バッファオーバーフローの一種である。2

専門家に聞いてみた(現場の先輩)

Q. どのように確認すれば良い?
A. エラーの発生を確認する。若しくはブラウザ上で操作に影響があればそれがオーバーフローしていると判断して良いでしょう。

Q. 実行環境は?
A. JavaScriptは一般的にブラウザで実行されるので、最もメジャーであるChromeで確認すれば良いでしょう。

検証方法

  • Chrome(バージョン:78.0.3904.108)
  • 実行時エラーが発生するか
  • ブラウザの挙動に変化はないか

まずはスタックオーバーフローを発生させてみた

今回検証に使用するコードはこちら

function push() {
  try {
    return push();
  } catch (e) {
    console.log(e);
  }
}
push();

結果

エラーが発生した。
RangeError: Maximum call stack size exceeded

キューオーバーフローが発生するか検証してみた

今回検証に使用するコードはこちら

enqueue()を抜け無ければ、延々とキューにタスクを詰め込む。

※無限ループに注意。

function enqueue() {
  while (1) {
    try {
      setTimeout(() => {console.log('詰めまくり!')}, 0);
    } catch (e) {
      console.log(e);
    }
  }
}
enqueue();

結果

エラーは発生しなかった。

無限ループで固まってしまったため強制終了。

ここに新たなトリビアが誕生した

キューオーバーフローになるようにあえてコードを実行すると、、、エラーは発生しない。

番外編

キューに積みまくった状態でスタックへぶち込むとどうなるのか検証してみた。

まずはこちらで最大値を計測する。

let n = 0;
function push() {
  try {
    ++n;
    return push();
  } catch (e) {
    console.log(`${n}個目のタスクでエラーでした。`);
  }
}
push();

結果

続いてこちらを実行する

ループ処理はこちらを参考にさせていただいた。3
想定では、enqueue()を抜けた後にキューに詰められたタスクがスタックに積まれるはずだが。。

function enqueue() {
  for (let i = 0; i < 10452; i++) {
    try {
      setTimeout(() => {() => {console.log('詰めまくり!')}}, 0);
    } catch (e) {
      console.log(e);
    }
  }
  // キューに積み切るまでの時間稼ぎ
  const ms = new Date();
  while (new Date() - ms < 100000);
}
enqueue();

結果

エラーは発生しなかった。

感想

あくまで予想だが、オーバーフローしないようにある程度分割してスタックに積んでいるのだろうか...?
はたまた、webapisが上手いことやってくれている...?
検証は以上となります。