Čekání na AJAX

Časované řetězce v jQuery

Jeden z nejužitečnějších pluginů pro jQuery je určitě jQuery timing, který mění celou jQuery knihovnu tak, abyste mohli mezi jednotlivé řetězené metody vkládat různá čekání, opakování a podmínky.

Poznámka: v češtině dochází trochu ke zmatení slova „řetězec“, který je většinou chápán jako překlad výrazu „string“ – tedy typ proměnné. Zde ale jde o překlad slova „chain“, který charakterizuje způsob zápisu volání metod, který se používá u jQuery.

Porovnejte následující příklady:

//jQuery:
$('#gameStart').click(function() {
    $(this)
        .hide()
        .parents('div.game')
        .find('img.game')
        .each(function() {
            $(this).show().click(function() {
                $(this).hide();
                var
                    el = $('#gameStart'),
                    cnt = el
                        .parents('div.game')
                        .find('img.game:visible')
                        .length;
                if (0 === cnt) {
                    el.show();
                }
            });
        });
});
//jQuery timing:
el.on('click')
    .hide()
    .parents('form')
        .find('input')
            .each($)
                .show().on('click').hide()
            .all()
        .end()
    .end()
    .show()
;

Máme tu jednoduchou hru, kde musíte kliknout na všechny ikony (obdoba hry Jacks). Všimněte si, že díky timing pluginu jsme ušetřili vytvoření 3 vnořených metod (které činí kód značně nepřehledným) a celý kód jsme zapsali jen pomocí řetězeného volání (chain calls) jQuery metod.

Stejně elegantně jde vyřešit i čekání:

//jQuery:
var el = $('.input');
el.addClass('pressed');
setTimeout(function() {
    el.removeClass('pressed');
    setTimeout(function() {
        el.hide();
    }, 100);
}, 1000); //setTimeout
//jQuery timing:
$('.input').addClass('pressed')
    .wait(1000).removeClass('pressed')
    .wait(100).hide()
;

Zatímco v jQuery je pro pozdržení potřeba vytvořit timeout and pak pomocí uzávěry použít existující proměnnou, v jQuery timing snadno zřetězíte metody za sebe a jen mezi ně vložíte volání metody wait().

Čekání

Základní funkcí je (jak už přímo název pluginu napovídá) čekání.

V základní podobě se jedná o mezeru vloženou mezi dvě metody:

//jQuery timing:
$(el).show().wait(100).hide();

//jQuery:
$(el).show();
setTimeout('$(el).hide()', 100);

Volání metody po wait() se pak automaticky pozdrží o daný počet milisekund.

Pokud po uplynutí dané doby nechcete volat jQuery metodu, ale potřebujete provést něco jiného, můžete metodě wait() předat callback:

$('body').hide().wait(100, function() {
    document.location = 'index.html';
});

Metodu wait() dokonce nemusíte volat nad elementem, ale můžete využít její globální obdobu:

$.wait(100, function() { ... });

Čekat ale nemusíte jen po určenou dobu, plugin umožňuje čekat i třeba na událost:

//jQuery timing:
$(el).wait('click').hide();
$(el).on('click').hide();

//jQuery:
$(el).one('click', function() {
    $(this).hide();
})

V tomto případě je použití metody wait() stejné jako použití metody one(). V obou případech dojde k tomu, že metody zapsané za wait()/one() se pozdrží do doby, než uživatel klikne na daný element. Důležité je ale uvědomit si, že metoda zde čeká pouze na první výskyt události.

Čekat můžete i na Deferred objekt nebo Promise nebo dokonce na funkci, která je vrací (takovou funkcí na například přímo funkce wait()):

var doubleClick = function() {
    return this.wait('click').wait('click');
}
//...
$(el).wait(doubleClick).hide();

Poslední možnost čekání je tzv. prázdné čekání, která znamená, že se čeká do doby, než se dokončí veškeré naplánované akce a animace:

$(el).wait(100).show();
//...
$(el).wait(200).addClass('progress');
//...
$(el).animate(...);
//...
//počkej na dokončení všech předchozích čekání a animací; pak počkej ještě 100ms a element schovej
$(el).wait().wait(100).hide();

Toto (prázdné) čekání si podrobněji ukážeme u metody join().

Další možností čekání je vyskočení z čekání a návrat k původnímu objektu. Pokud v řetězci použijete metodu wait() (nebo jakoukoliv, která vrací Deferred), všechny následující metody pak budou volány se spožděním. Pokud pak na závěr chcete zavolat nějakou metodu hned (nebo např. začít nové čekání), můžete k tomu použít speciální zápis „._.“ (jde vlastně o referenci uloženou po jménem „podtržítko“).

//špatně:
$(el).show().wait(100).hide().children().show()
//dobře:
$(el).show().wait(100).hide()._.children().show()
//taky dobře:
$(el).show()
    .children().show().end()
.wait(100).hide()

V prvním příkazu zobrazíme prvek, po 100ms ho zase skryjeme a následně necháme zobrazit všechny vnořené prvky – což dopadne špatně, protože prvek bude vidět jako prázdný a následně vnořené prvky nebudou vidět, protože jejich rodič je skrytý.

Naproti tomu druhý příkaz dopadne dobře, protože zobrazí prvek, nastaví čekání na 100ms, které ho opět skryje, a pak (již mimo čekání) zobrazí i všechny vnořené prvky. Rodič i potomci se tak zobrazí okamžitě bez čekání.

Další přklad pro různá čekání:

//špatně
$(el)
    .wait('click').addClass('selected')
    .wait('keypress').addClass('selected')
    .wait(1000).hide();
//dobře
$(el)
    .wait('click').addClass('selected')
    ._.
    .wait('keypress').addClass('selected')
    ._.
    .wait(1000).hide();

První příkaz se bude chovat poněkud podivně, protože uživatel bude muset nejprve na prvek kliknout, následně stisknout klávesu a sekundu poté se prvek skryje.

Druhý příkaz již dává větší smysl, protože vyžaduje, aby uživatel na prvek kliknul nebo stisk klávesu, a nezávisle na tom, co uživatel udělá (nebo i když nic neudělá), se po sekundě skryje – může jít tedy o nějakou hru na test rychlosti (příp. reklamu typu „rychle klikněte, než nabídka vyprší“).

Opakování

Dalším důležitým rozšířením je opakování:

$(el).addClass('highlight')
    .repeat().wait(100).toggleClass('highlight')
    .until(10).removeClass('highlight')
;

Tento kód zvýrazní daný prvek, pak počká 100ms, zase zvýraznění zruší, počká dalších 100ms, zase zvýraznění přidá, a po deseti opakováních (a tedy uplynutí 1 sekundy) nakonec zvýraznění zruší. Celý efekt tedy vypadá tak, že prvek 5× blikne.

Zápis repeat().wait() se dá zkrátit a doba čekání se dá přímo předat metodě repeat():

$(el).repeat(100).toggleClass('xxx').until(10);

Pokud na konci nezavoláte metodu until(), bude opakování trvat pořád:

//blikající objekt (
$(el).repeat(100).toggleClass('highlight');
//blikání začne okamžitě:
$(el).repeat(100, true).toggleClass('highlight');

Do repeat() můžete předat i událost a pak dojde k vyvolání následných metod po každé takové události:

$(el).repeat('click').hide().wait(100).show();
//odpovídá volání:
$(el).on('click').hide().wait(100).show();

Do metody repeat lze předat i funkci, která se zavolá při každém opakování. Do parametrů této funkce se pak dostane vždy aktuální číslo volání:

$(el).repeat(function(i) { alert(i); }).until(3);
// vyhodí alerty "0", "1" a "2"

$(table).repeat().repeat(function(x, y) {
    this.append($('span').text(x * y));
}).until(10).until(10);
//vypíše malou násobilku od 0 do 9

Během opakování (a vlastně i kdekoliv jinde díky tomuto pluginu) můžete použít speciální metody „.$()“. Metoda .$() funguje jako základní metoda $() (resp. jQuery()), ale lze ji zavolat uprostřed řetězce a změnit tím prvky, se kterými pracujete. Vrátit se zpět může metodou .end() (stejně jako u metod .filter(), .find(), apod.):

$(el).addClass('highlight')
    .repeat(100).toggleClass('highlight')
        .$(progress).append('<span>').text('.')
    .end() //return back to el
    .until(10).removeClass('highlight');

Tento příklad, který po 1 sekundu zvýrazňuje prvek, byl již uveden; zde ale navíc přidává do prvku progress tečky, takže víte, jak dlouho ještě bude blikání trvat.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.

Tato stránka používá Akismet k omezení spamu. Podívejte se, jak vaše data z komentářů zpracováváme..