0

When the following code is run:

(function recur() {
    recur()
})()

the following error is raised —

Uncaught RangeError: Maximum call stack size exceeded

— with the stack filled with references to the function (recur).

So why does the following code:

(function recur() {
    try {
        recur()
     } catch (error) {
        recur()
     }
})()

even though the error is caught in the try block, not return the error in the catch block? Or at least complain about the function overflowing the call stack?

When the code is run, it does pause all other non-asynchronous code from executing, but still... no errors?! What's going on here?


EDIT:

This behavior is especially weird with code like this:

(function notRecur() {
    try {
        Symbol() + 2
    } catch (error) {
        Symbol() + 2
    }
})()

that returns a TypeError when executed.

Just another question to experiment with, thanks for reading through and replying.

Lapys
  • 936
  • 2
  • 11
  • 27
  • 1
    For every `RangeError` that could get thrown, you create a *new* `catch` handler. If you're handling *every* `RangeError`, where do you expect an *unhandled* `RangeError` to come from? – Kirk Larkin Sep 03 '18 at 20:23
  • I'm still a bit lost. What I figured would happen is that the `RangeError` would get thrown in the `catch` handler preventing the script from calling the `recur` function again. – Lapys Sep 03 '18 at 20:29
  • Possibly https://stackoverflow.com/questions/6095530/maximum-call-stack-size-exceeded-error will help – Varit J Patel Sep 03 '18 at 20:30
  • 1
    The `RangeError` is *thrown* in the `try` block and *caught* in the `catch` block. Once you've *caught* the `RangeError`, it's like it never happened. Then, in your `catch` block, you call `recur` again. This time around, you create a whole *new* `catch` block to handle the next `RangeError` that occurs, etc, etc. You have tonnes of these `catch` handlers due to the recursion - not many of them will actually see a `RangeError` occur, but when they do, they squash it and continue on with the recursion. – Kirk Larkin Sep 03 '18 at 20:31
  • 3
    RE your edit - that's *entirely* different. For that, just run `Symbol() + 2` completely standalone and you'll get a `TypeError`. There's no recursion involved here - so the error occurs in the `try` and is then handled in the `catch`. In your `catch`, you generate the same error but there's no `catch` for this as there's *no recursive creation of `catch` handlers*. – Kirk Larkin Sep 03 '18 at 20:36

2 Answers2

2

You're getting an infinite loop of catched RangeError exceptions.

It will execute the recur call within the try block until the maximum call stack size is exceeded. Thereafter the catch block will be executed the first time and call recur again - leading to a RangeError exception - that's caught in the catch block - and so on.

To help visualize this, you can print the stack trace in your catch block before starting the recursion:

(function recur() {
    try {
        recur()
     } catch (error) {
        console.log(error.stack);
        recur()
     }
})()
JanS
  • 2,065
  • 3
  • 27
  • 29
2

If you got endless recursion, the call stack gets filled up until it reaches a memory limit and crashes, in that case the error bubbles up and unwinds the stack:

 call > call > call > call > call > | memory limit
    <----------------------------- error

Now you directly catch that and retry:

 call > call > call > call > call  | memory limit
                           < error |
                           > call  |
                           < error |
                           > call  |
                           < error |
                           > call  |
                           ...

Although it looks very strange it doesnt fill up memory. However it blocks the browsers thread, so the browser might kill the whole thread after some time.

Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151