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 の再帰はなるべく避けよう」という辺りで落ち着けておきます。