htsign's blog

ノンジャンルで書くつもりだけど技術系が多いんじゃないかと思います

Promise を再帰させるとどうなるか

ただの興味本位です。

以下のコードを各環境で動かしていきます。

const p = n => new Promise(resolve => { console.log(n); resolve(p(n + 1)); });
p(1);

なるべく公平を期すため、ブラウザの場合は about:blank にて実行します。

環境

PC1:

種別 詳細
OS Windows 10
CPU AMD Rizen 5 1600
MEM DDR4 PC4-24000 16GB x2 (空き 20000MB程度)

PC2:

種別 詳細
OS macOS 10.14.6 (Mojave)
CPU Intel Core i5 5250U
MEM LPDDR3 PC3-12800 4GB (空き1000MB程度)

結果

環境 再帰回数 備考
Edge 44 1000 20回置きにウェイトが入る。終了時は特に出力なし
Safari 3674 コンソールにはエラーが表示されず、
ブラウザページにポップアップでMaximum call stack size exceeded.と表示され終了
Firefox 69 (PC1) 582 too much recursion の例外で終了
Firefox 69 (PC2) 2946 too much recursion の例外で終了
Chrome 77 (PC1) 1934 RangeError: Maximum call stack size exceeded の例外で終了
Chrome 77 (PC2) 1929 RangeError: Maximum call stack size exceeded の例外で終了
node 10.16.3 (PC1) 1818 エラーを吐かずにクラッシュして終了
node 10.16.3 (PC2) 1847 RangeError: Maximum call stack size exceeded の例外で終了
node 12.11.1 (PC1) 1806 エラーを吐かずにクラッシュして終了
node 12.11.1 (PC2) 1835 RangeError: Maximum call stack size exceeded の例外で終了

この規則性のない結果から、おそらく Promise における再帰については厳密な仕様はなく実装依存であることが推定されますが、仕様書のどの辺りを見ればよいのか分からず…。
同じバージョンでも環境によって結果が異なるので、メモリ等の状態によっても変わるのかなと思いますが、ブラウザのソースコード読む気力もなく、「とりあえず Promise の再帰はなるべく避けよう」という辺りで落ち着けておきます。