ajax dummy url klic na onbeforeunload

Ko uporabnik zapre okno, bi rad znotraj onbeforeunload/onunload dogodka sprožil ajax klic za statistiko. Jquery omogoča, da nastavim async na false in bo čakal da ajax klic vrne rezultat. Drugače do klica sploh ne bo prišlo, ga prej prekine. Problem je, ker lahko čaka na rezultat tudi sekundo ali več in do takrat uporabniku ne zapre okna.

Prišel sem na idejo, da bi dodal zraven še en ajax klic na neobstoječ url in temu klicu nastavim async false, pravemu pa true. Ajax klic v približno 50ms sekundah vrne rezultat, da url ne obstaja. Kar je dovolj, da sproži na strežnik ajax klic pravega url-ja (ne rabim odgovora, samo da se sproži).

window.onbeforeunload = (function(){
jQuery.ajax({
  type: "GET",
  url: statsUrl,
  data: "windowClosed=1&id="+JSON.stringify(sendData),
  async:true
});

var dummyUrl = 'http://'+Math.random().toString(36).substring(2)+'.com';
jQuery.ajax({
  type: "GET",
  url: dummyUrl,
  async:false
});
}());

Vprašanje: Malo me skrbi če zna bit kaka težava s tem neobstoječim url-jem. A vidi kdo kak potencialen problem?

6 odgovorov

Kaj pa, če bi poskusil s setTimeout?

$(window).on("beforeunload", function (e) {
    setTimeout(function(){
        $.ajax({
            type: 'GET',
            async: false,
            url: "http://neki..."
        });
    }, **50***);
});
  • tu nastaviš timeout v ms. Kode pa nisem testiral, zgolj razmišljam "na glas" - probaj se mal poigrat :)

Tnx, tole dela samo v FF, čeprav mi ni jasno zakaj dela, ker v tem primeru naj bi timeout zavlekel samo to kdaj naj se ajax klic začne in ne koliko časa naj traja. V IE to ne dela, dela pa tole (ne dela pa v FF):

var did = false;
  do {
   curDate = new Date();
    if(!did){
    jQuery.ajax({
      type: "GET",
      url: statsUrl,
      data: "closed=1&id="+JSON.stringify(sendData),
      async:true
    });
    did = true;
    }
   }
  while(curDate-date < 50);

To je bolj smiselno in ne vem zakaj v FF to ne dela. Da ne bo treba delat if pogojev za browserje bom verjetno uporabil kar tisto kar sem na začetku napisal. Bom pa dal namesto dummy url-ja kar url do tega .js fajla kjer je ta scripta. Ker je ta .js že naložen ga ima browser v cachu in bo samo cca 20ms zamika kolikor rabi da potegne iz keša (še vedno dovolj da sproži tisti ajax klic in ne preveč).

pod kaj smatraš da v FF ne dela? sploh nič ne naredi? vrže error?

kot drugo pa, dvomim da bo tole delovalo. Preprosto prehitro se zapre okno, da bi ti lahko vmes še poslal zahtevek.

Če hočeš ugotoviti, kdaj uporabnik zapre stran, boš moral drugačne pristope uporabiti.

Se strinjam s freakmanom, tole je ful nezanesljivo, hkrati pa se mi zdi tole nekaj, čemu se reče "code porn" :) Kakšni pa so te podatki, ki bi jih ti poslal na strežnik?

A si mogoče razmišljal o obratnem pristopu: namesto da loviš, kdaj je uporabnik zapustil stran raje preverjaš, koliko časa je uporabnik sploh na strani? Kot nek "ping" sistem, ki se sproža vsakih x (300, 500, 1000,...) milisekund in javlja, da je uporabnik še na strani?

Ideja nr. 2: v čem maš pa napisan backend? A imaš na voljo kakšne 'OnSessionEnd' oz. kakšne podobne server-side evente, na katere bi se lahko "obesil"?

V FF tista zgornja koda sicer počaka 50ms, ampak šele za tem izvede ajax klic, kar je malo nelogično, ker je ajax znotraj do.

Drugače pa sem testiral v IE, Safari, FF, Chrome in metoda z 2 ajax klicoma povsod dela, tudi če ima samo 11ms časa je dovolj da sproži klic. Problem imam le preko https, tam pa ne dela kot bi moralo.

Ping sistem ne pride v poštev, bo preveč zahtevkov, ker gre za modul in bodo takoj "pizdevali". Ne rabi bit 100% proofed, dovolj je 80%, glede na testiranja ki sem jih opravil pa verjamem da je ta metoda 90+% proofed. Podatka ki ju bom poslal sta samo id in čas v ms.

Samo ena malenkost.
Pri sync ajax klicih je kul če nastaviš še timeout in s tem pač forcaš konec.