Блокировка функции "wait" в javascript?

Как часть проекта Javascript, над которым я работаю, есть некоторые синхронные вызовы ajax (я думаю, это делает его "sjax", но я отвлекаюсь). Теперь я пишу панель отладки, которая позволит мне протестировать сайт с некоторыми искусственно смоделированными сетевыми условиями, обернув $.ajax. Простые вещи: фальсификация ответа на 500 и т.д., А вызов ajax занимает гораздо больше времени.

Для асинхронных вызовов это просто. Когда возвращается реальный ответ, добавьте setTimeout, чтобы дождаться искусственного времени отклика, прежде чем запускать обратный вызов. Однако это явно не работает с синхронными вызовами, поскольку setTimeout не является синхронным.

Итак, есть ли способ заставить Javascript-программу выполнять блокирующее ожидание на определенное количество времени?

Единственное, что я мог подумать, было бы примерно так:

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

Есть ли лучшее решение?

(Кроме того, предположим, что есть хорошая причина блокировки вызовов ajax... :-\)

Ответ 1

Не делайте этого на уровне JavaScript. Получите прокси-сервер, например Fiddler, и настройте AutoResponder, чтобы задержать вызов на время период.

Ответ 2

Если для целей отладки требуется искусственная задержка:

alert('block me one more time');

Нет никакого разумного другого подхода, чтобы иметь код блокировки в ECMAscript. Поскольку Javascript выполняется в том же потоке ( "поток пользовательского интерфейса" ), который браузеры используют для рендеринга DOM и некоторых других вещей, весь показ был разработан, чтобы ничего не блокировать.

Конечно, вы можете подделать его, используя цикл, но это извращение шоу.

Ответ 3

Я понял, что этот код может помочь

// 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()

И тест...

// // // 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 // // //