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');
});  
(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');
});  
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. , .