Nick Zuber
Nick Zuber

Reputation: 5637

Waiting for function with a setTimeout to complete without tampering with that function

So basically I have a function that has a setTimeout within it like so:

function foo(){
    console.log('starting');
    setTimeout(function(){
        console.log('done');
    }, 2000); // some arbitrary delay
}

and I want to call this function, have it truly complete, and then call a second function when it has ended:

foo();
secondFunction();

Is there a way that I can wait for foo() to finish running, including its setTimeout call, before secondFunction() fires? I suspect there is a way to do this with Promises because I've seen this problem solved with Promises before, however all the solutions I've seen includes tampering with the initial function that has the setTimeout; in my situation I cannot alter foo() at all.

Is there a way to solve this problem without altering foo() at all? This means I can't create Promises inside foo() nor can I add a callback function to foo() explicitly.

Upvotes: 3

Views: 149

Answers (1)

Alnitak
Alnitak

Reputation: 340045

You can monkey-patch setTimeout because it's a property of the global object:

function trapTimeout() {
    return new Promise(function(resolve, reject) {
        var setTimeout = window.setTimeout;
        window.setTimeout = function(cb, delay) {
            var args = [].slice.call(arguments, 2);
            setTimeout.call(window, function() {
                window.setTimeout = setTimeout;
                cb.apply(null, args);
                resolve();
            }, delay, ctx);
        }
    });
}

var trap = trapTimeout();
foo();
trap.then(function() { console.log('really done') });

This is a moderately nasty hack. It could well barf if something else creates a timer after this code (since the .then call doesn't stop any following code or the event loop from running, and the monkey patching remains in place until after the timeout is triggered).

Upvotes: 3

Related Questions