How to catch an error

I have a recursive function with an asynchronous interface that will probably exceed the depth limits of the stack when called:

function f(x, cb) {
    if (x === 0) {
        cb();
    } else {
        f(x - 1, cb);
    }
}

f(1e6, function() {
    console.log('done');
});  // BOOM

(and yes, it must be recursive, rewrite it as iterative, not viable).

I can solve this by making a recursive call asynchronously (e.g. via setTimeoutor window.postMessage, which is supposedly faster):

function f(x, cb) {
    if (x === 0) {
        cb();
    } else {
        setTimeout(function() {
            f(x - 1, cb);
        }, 0);
    }
}

f(1e6, function() {
    console.log('done');
});  // ok

But it is much slower. Therefore, I want to make an asynchronous call only when it otherwise causes a stack overflow. Sort of

function f(x, cb) {
    if (x === 0) {
        cb();
    } else {
        if (getCurrentStackDepth() == getMaxStackDepth() - 42)
            setTimeout(function() {
                f(x - 1, cb);
            }, 0);
        } else {
            f(x - 1, cb);
        }
    }
}

or, if this is not possible, at least detect when an overflow occurs and try again asynchronously. Something along the lines

function f(x, cb) {
    if (x === 0) {
        cb();
    } else {
        try {
            f(x - 1, cb);
        } catch (e) {
            if (isStackOverflowError(e)) {
                setTimeout(function() {
                    f(x - 1, cb);
                }, 0);
            } else {
                throw e;
            }
        }
    }
}

? Function.prototype.caller , es5-es6. , .

+4
2

, (JS), , getCurrentStackDepth. , .

. , JS- , RangeError. , , isStackOverflowError,

function isStackOverflowError(e) {
    return (e instanceof RangeError) && /.+stack.+size.+/.test(e.message);
}

, -2, . , .

+1

:

function f(x, cb) {
    if (x === 0) {
        cb();
    } else {
      try {
        f(x - 1, cb);
      } catch (e) {
        setTimeout( function() { f(x-1, cb); }, 0 );
      }
    }
}

f(100000,function(){console.log("Done!")})

, . , . "", , , .

. .

0

Source: https://habr.com/ru/post/1612960/


All Articles