Question

As part of a Javascript project I'm working on, there are some synchronous ajax calls (I guess that makes it "sjax", but I digress). I'm now writing a debugging panel which would allow me to test out the site with some artificially simulated network conditions by wrapping $.ajax. Simple things: faking a 500 response etc, and making the ajax calls take much longer.

For the asynchronous calls, it's simple. When the real response comes back, add a setTimeout to make it wait for the artificial response time before triggering the callback. However, this doesn't work with the synchronous calls obviously, since setTimeout isn't synchronous.

So, is there a way to make a Javascript program perform a blocking wait for a set amount of time?

The only thing I could think of would be something like this:

function wait(ms) {
    var start = +(new Date());
    while (new Date() - start < ms);
}

Is there a better solution?

(Also, please assume there's a good reason for the blocking ajax calls... :-\)

No correct solution

OTHER TIPS

Do not do it on the JavaScript level. Get a proxy such as Fiddler and set up an AutoResponder to delay the call by a time period.

If it's just for debugging purposes to have an artificial delay:

alert('block me one more time');

There is no reasonable other approach to have a blocking code in ECMAscript. Since Javascript is executed in the same thread ("UI thread") which browsers use to render the DOM and to certain other things, the whole show was designed not to block anything.

Of course you can fake it by using a loop, but its a perversion of the show.

I figured this code might help

// execute code consecutively with delays (blocking/non-blocking internally)
function timed_functions() 
{
    this.myfuncs = [];
    this.myfuncs_delays = []; // mirrors keys of myfuncs -- values stored are custom delays, or -1 for use default
    this.myfuncs_count = 0; // increment by 1 whenever we add a function
    this.myfuncs_prev   = -1; // previous index in array
    this.myfuncs_cur    = 0; // current index in array
    this.myfuncs_next  = 0; // next index in array
    this.delay_cur     = 0; // current delay in ms
    this.delay_default = 0; // default delay in ms
    this.loop = false;      // will this object continue to execute when at end of myfuncs array?
    this.finished = false;  // are we there yet?
    this.blocking = true;   // wait till code completes before firing timer?
    this.destroy = false;   // <advanced> destroy self when finished


    // handle next cycle execution
    this.next_cycle = function() {
        var that  = this;
        var mytimer = this.delay_default;

        if(this.myfuncs_cur > -1)
            if(this.myfuncs_delays[this.myfuncs_cur] > -1)
                mytimer = this.myfuncs_delays[this.myfuncs_cur];

        console.log("fnc:" + this.myfuncs_cur);
        console.log("timer:" + mytimer);
        console.log("custom delay:" + this.myfuncs_delays[this.myfuncs_cur]);

        setTimeout(function() {
        // times up! next cycle...
        that.cycle(); 

        }, mytimer);
    }



    this.cycle = function() {

        // now check how far we are along our queue.. is this the last function?
        if(this.myfuncs_next + 1 > this.myfuncs_count)
        {
            if(this.loop)
            {
                console.log('looping..');
                this.myfuncs_next = 0;
            }
            else
                this.finished = true;
        }


        // first check if object isn't finished
        if(this.finished)
        return false;

        // HANDLE NON BLOCKING //
        if(this.blocking != true) // blocking disabled
        {
            console.log("NOT BLOCKING");
            this.next_cycle();
        }


        // set prev = current, and current to next, and next to new next
        this.myfuncs_prev = this.myfuncs_cur;
        this.myfuncs_cur  = this.myfuncs_next;
        this.myfuncs_next++; 

        // execute current slot
        this.myfuncs[this.myfuncs_cur]();




        // HANDLE BLOCKING
        if(this.blocking == true)  // blocking enabled
        {
            console.log("BLOCKING");
            this.next_cycle();
        }

        return true;
    }; // END :: this.cycle





    // adders 
    this.add = {
        that:this,

        fnc: function(aFunction) { 
        // add to the function array
        var cur_key = this.that.myfuncs_count++;
        this.that.myfuncs[cur_key] = aFunction;
        // add to the delay reference array
        this.that.myfuncs_delays[cur_key] = -1;
        }
    }; // end::this.add




    // setters
    this.set = {
        that:this, 

        delay:          function(ms)    {  
            var cur_key = this.that.myfuncs_count - 1;
            // this will handle the custom delay array this.that.myfunc_delays
            // add a custom delay to your function container

            console.log("setting custom delay. key: "+ cur_key + " msecs: " + ms);
            if(cur_key > -1)
            { 
                this.that.myfuncs_delays[cur_key] = ms; 
            }

            // so now we create an entry on the delay variable
        },  // end :: this.set.delay(ms)

        delay_cur:      function(ms)        { this.that.delay_cur = ms;         },
        delay_default:  function(ms)        { this.that.delay_default = ms;         },
        loop_on:          function()        { this.that.loop = true; }, 
        loop_off:         function()        { this.that.loop = false; },
        blocking_on:      function()        { this.that.blocking = true; }, 
        blocking_off:     function()        { this.that.blocking = false; },

        finished:           function(aBool) { this.that.finished = true; }
    }; // end::this.set    




    // getters
    this.get = {
        that:this, 

        delay_default: function() { return this.that.delay_default; },
        delay_cur:     function() { return this.that.delay_cur; }
    }; // end::this.get     

} // end ::: timed_functions()

And Test...

// // // BEGIN :: TEST // // //

    // initialize
    var fncTimer = new timed_functions;

    // set some defaults
    fncTimer.set.delay_default(1000); // set a default delay between function blocks
    fncTimer.set.blocking_on(); // next timer begins count before code is executed
    fncTimer.set.blocking_off(); // next timer begins count after code is executed
    // fncTimer.set.loop_on(); // when finished start over
    // fncTimer.set.loop_off();


    // BEGIN :: ADD FUNCTIONS (they will fire off in order)
    fncTimer.add.fnc(function() {
        console.log('plan a (2 secs)');
    });
    fncTimer.set.delay(2000); // set custom delay for previously added function


    fncTimer.add.fnc(function() {
        console.log('hello world (delay 3 seconds)');
    });
    fncTimer.set.delay(3000);


    fncTimer.add.fnc(function() {
        console.log('wait 4 seconds...');
    });
    fncTimer.set.delay(4000);
    // END :: ADD FUNCTIONS


    // NOW RUN
    fncTimer.cycle(); // begin execution 


// // // END :: TEST // // //
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top