Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[JS] onBeforeUnload in Firefox en IE

Pagina: 1
Acties:
  • 1.437 views sinds 30-01-2008
  • Reageer

  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Topicstarter
Ik ben bezig een chatbox te ontwikkelen die gebruik maakt van JavaScript en PHP (met AJAX). Als de gebruiker de subpagina domein.nl/chatbox opent, dan wordt hij toegevoegd aan een "online users" rijtje. Als de gebruiker de pagina verlaat moet hij weer uit dat rijtje verdwijnen. Ik doe dat als volgt:

1. De chatbox pagina heeft een window.onBeforeUnload event listener die via AJAX de gebruiker uit de database verwijdert als hij de pagina verlaat.
2. De gebruiker doet elke halve seconde via AJAX een request om nieuwe berichten. Als ik twee seconden lang geen nieuwe aanvraag binnenkrijg, ga ik ervanuit dat de gebruiker offline is en verwijder ik hem uit de database. Dit kan door elke paar seconden een PHP script te draaien (wat ik nog moet schrijven :P)

Stap 2 is nodig omdat onBeforeUnload niet betrouwbaar is; een gebruiker kan javascript uitschakelen nadat hij de chatbox opent, of de stekker uit zijn modem trekken. In beide gevallen vuurt BeforeUnload niet en blijft de user aanwezig in de database. Toch vind ik het de moeite waard om BeforeUnload te gebruiken, omdat 99% van de gebruikers netjes de pagina zal verlaten of de browser zal sluiten.

Het probleem is dat Firefox en IE een andere interpretatie van het BeforeUnload event hebben. IE7 vuurt het event af als de gebruiker wegsurft naar een willekeurige andere pagina, ook als hij klikt op een internal anchor. FF2 doet dat niet. In de firefox changelog heb ik een bugfix gevonden die volgens mij dit gedrag veroorzaakt. Andere browsers heb ik niet getest.

Als FF gebruikers dus op een interne link klikken terwijl ze in de chatbox zitten, dan blijft hun status online. Ik zoek een efficiënte manier om firefox een event te laten afvuren op het moment dat de gebruiker de pagina verlaat, ook als hij dat doet door een andere subpagina te kiezen.

Ik zou misschien de mouseclicks kunnen afluisteren om te zien of de gebruiker op een interne link klikt, maar dat vind ik een 'vieze' oplossing.
Een workaround is alle interne anchors vervangen door externe, maar dat is geen echte oplossing en bovendien erg onhandig.

edit: het event lijkt soms wel te vuren. Als een alert("hi"); aan de event handler toevoeg, voor of na de AJAX request, vuurt hij altijd. :?

[ Voor 3% gewijzigd door Bozozo op 31-12-2007 14:20 ]

TabCinema : NiftySplit


  • Juup
  • Registratie: Februari 2000
  • Niet online
Okee dus als iemand op een anchor klikt dan wil jij dat de onBeforeUnload wordt afgevuurd.
Misschien kun je onload door alle ElementsByTagName("a") heenlopen en er een onClick event aanhangen?

Een wappie is iemand die gevallen is voor de (jarenlange) Russische desinformatiecampagnes.
Wantrouwen en confirmation bias doen de rest.


  • Zamalan
  • Registratie: September 2007
  • Laatst online: 26-02-2015

Zamalan

Whine Connaisseur

Als ik
JavaScript:
1
this.onbeforeunload = function(){alert("close");};
op een pagina zet dan komt die alert enkel als ik van de pagina weg ga.
Als ik een interne link klik (<a href="#test">) dan toont hij niks. Logish want de gebruiker gaat niet van de pagina en de chat zou in principe nog open moeten staan.

(getest in FF2 en IE6)

Volledig voorbeeld
HTML:
1
2
3
4
5
6
7
8
9
10
11
12
<html>
 <head>
  <title>lol</title>
  <script>
    this.onbeforeunload = function(){alert("close");};
  </script>
 </head>
 <body>
  <a href="#test" >test</a>
  <div id="test">Lorem ipsum</div>
 </body>
</html>

[ Voor 31% gewijzigd door Zamalan op 31-12-2007 14:36 ]

MSI GX660 --- i5 460M /// 4GB DDR3 /// Mobility Radeon HD5870 /// 1920x1080 /// 500GB


  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Topicstarter
@Jaaap: bedankt, maar dat vind ik geen nette oplossing. Als er echt niks anders lukt zou ik dat wel willen toepassen, maar liever niet.
@Zamalan: een interne anchor is schijnbaar ook <a href="/?page=nietdechat">Nietdechat</a>. Helaas gebruik ik dat soort links om aan php te vertellen welke pagina de gebruiker wil zien. Als je op zo'n link klikt verlaat je wel degelijk de chat.

[ Voor 8% gewijzigd door Bozozo op 31-12-2007 14:36 ]

TabCinema : NiftySplit


  • Zamalan
  • Registratie: September 2007
  • Laatst online: 26-02-2015

Zamalan

Whine Connaisseur

Bozozo schreef op maandag 31 december 2007 @ 14:35:
@Jaaap: bedankt, maar dat vind ik geen nette oplossing. Als er echt niks anders lukt zou ik dat wel willen toepassen, maar liever niet.
@Zamalan: een interne anchor is schijnbaar ook <a href="/?page=nietdechat">Nietdechat</a>. Helaas gebruik ik dat soort links om aan php te vertellen welke pagina de gebruiker wil zien. Als je op zo'n link klikt verlaat je wel degelijk de chat.
Als ik die link met de mijne vervang doet hij het nog steeds...

MSI GX660 --- i5 460M /// 4GB DDR3 /// Mobility Radeon HD5870 /// 1920x1080 /// 500GB


  • Juup
  • Registratie: Februari 2000
  • Niet online
Bozozo schreef op maandag 31 december 2007 @ 14:35:
@Zamalan: een interne anchor is schijnbaar ook <a href="/?page=nietdechat">Nietdechat</a>. Helaas gebruik ik dat soort links om aan php te vertellen welke pagina de gebruiker wil zien. Als je op zo'n link klikt verlaat je wel degelijk de chat.
Dan is dat een bug.
Eventueel kun je op de server mod_rewrite gebruiken om de url te herschrijven naar /page/nietdechat ofzo.

Een wappie is iemand die gevallen is voor de (jarenlange) Russische desinformatiecampagnes.
Wantrouwen en confirmation bias doen de rest.


  • Borizz
  • Registratie: Maart 2005
  • Laatst online: 24-09 20:59
Bozozo schreef op maandag 31 december 2007 @ 14:13:
2. De gebruiker doet elke halve seconde via AJAX een request om nieuwe berichten. Als ik twee seconden lang geen nieuwe aanvraag binnenkrijg, ga ik ervanuit dat de gebruiker offline is en verwijder ik hem uit de database. Dit kan door elke paar seconden een PHP script te draaien (wat ik nog moet schrijven :P)
Waarom zou je daarvoor een script op de achtergrond draaien (en dan zeker elke paar seconden)? Je kan dat toch ook doen om de zoveel tijd dat je een (xmlhttp) request van een andere gebruiker krijgt. En zolang er niemand anders is ingelogd, maakt het ook niet uit of de gebruiker nog online staat.

Je kan dan ook een check maken op basis van tijd, dat als je de laatste 60 seconden (ik zeg maar wat) nog niet gekeken hebt of mensen uitgelogd zijn, dat je dat dan op dat moment doet. Dat levert dan voor maximaal 1 persoon per 60 seconden een (waarschijnlijk onmerkbare) vertraging op voor zijn request.

[ Voor 41% gewijzigd door Borizz op 31-12-2007 20:49 . Reden: ik had nog geen reply gemaakt :p ]

If I can't fix it, it ain't broken.


  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Topicstarter
Ik wou nog even laten weten dat ik het probleem heb omzeild door gewoon onUnload te gebruiken, en niet onBeforeUnload. Ik was eerder gedwongen om onBeforeUnload te gebruiken omdat anders niet alle code werd uitgevoerd, maar dat blijkt (volkomen toevallig) niet meer nodig te zijn na een hoop wijzigingen in het script.

@Borizz: het is veel makkelijker om gewoon elke paar secoden een scriptje te draaien, als je server dat tenminste ondersteunt. Hetzelfde geldt voor bijvoorbeeld het verwijderen van account-aanvragen die binnen 48 uur niet zijn bevestigd middels email.

edit: alsof de duivel ermee speelt... de eerste de beste nieuwe feature die ik toevoeg zou weer veel profijt hebben van onBeforeUnload :|

[ Voor 11% gewijzigd door Bozozo op 02-01-2008 10:19 ]

TabCinema : NiftySplit


  • Borizz
  • Registratie: Maart 2005
  • Laatst online: 24-09 20:59
Bozozo schreef op woensdag 02 januari 2008 @ 09:57:
@Borizz: het is veel makkelijker om gewoon elke paar secoden een scriptje te draaien, als je server dat tenminste ondersteunt. Hetzelfde geldt voor bijvoorbeeld het verwijderen van account-aanvragen die binnen 48 uur niet zijn bevestigd middels email.
Makkelijker wel ja (in eerste instantie), maar afhankelijk van het aantal gebruikers van je applicatie, draait je script misschien 99% van de tijd voor niets. En mocht je de applicatie ooit op een andere server willen zetten dan moet je daar weer opnieuw dat proces op de achtergrond instellen. Terwijl het anders een kwestie is van je applicatie kopieren naar de nieuwe server en draaien maar.

Ik zeg niet dat het verkeerd is om het op de achtergrond te draaien, maar er zijn in ieder geval ook andere oplossingen.

If I can't fix it, it ain't broken.


  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Topicstarter
edit: oplossing onderaan deze post!

Goed, ik moét unbeforeunload gebruiken... maar ik krijg het niet aan de praat in FF. Ik ben nu al een paar uur aan het debuggen en ik heb de volgende dingen ontdekt:

- Het probleem ligt niet bij het interne linken. Als ik gewoon alert("bye bye") zeg, bij window.onbeforeunload, is er niets aan de hand. Zowel IE als FF reageren bij het verlaten van de pagina, op wat voor manier dan ook.
- Het probleem ligt bij AJAX, in combinatie met onbeforeunload
- IE functioneert zoals je zou verwachten;
- FF niet.

Hier een voorbeeld van hoe idioot het probleem in firefox is:
- Als de chatbox wordt verlaten, wordt een AJAX request gedaan naar signoff.php. Dat logt de gebruiker uit en schrijft daarna "... left the chatbox" in de chatbox.
- om te testen laat ik signoff.php ook "test" echoën.
- in javascript wordt bij onbeforeunload een functie 'signoff' aangeroepen, die het AJAX request doet. Als de readystate van dit request 4 wordt, dan wordt een functie 'report' aangeroepen
- de functie report geeft een alert met daarin de response van de server op het AJAX request.

Resultaat:
- In IE word ik netjes uitgelogd als ik de pagina verlaat. Ik zie een alert met "test". Ik zie niet mijn eigen "...left the chatbox" verschijnen in de chatbox, terwijl de browser wacht tot ik in de alert op OK klik.
- In FF is het gedrag niet elke keer hetzelfde. Meestal zie ik bij het verlaten van de pagina een lege alert. Dat is volgens mij een teken dat het AJAX request wel is begonnen, maar is gecancelled waardoor de readystate naar 4 gaat maar er geen response is. Ik word niet uitgelogd (zichtbaar in database).
- Soms (een op de vijf keer oid) word ik wél uitgelogd. Ik zie dan bij het verlaten van de pagina een lege (!!!!) alert, terwijl op de achtergrond "... left the chatbox" verschijnt. Het random wisselen van de twee gedragingen in Firefox is waarschijnlijk het gevolg van een andere AJAX request, die elke halve seconde om nieuwe chatberichten vraagt via setTimeout. Als ik deze functie uitschakel krijg ik alleen nog gedraging 1.

Het probleem in een notendop: Firefox breekt AJAX requests af ergens vlak na het plaatsvinden van het onBeforeUnload event.

Ik heb al vanalles zitten Googelen maar ik kan niemand vinden die hetzelfde probleem is tegengekomen. Ik ben echt ten einde raad, en ik erger me aan het feit dat Firefox minder goed werkt dan Internet Explorer :P

[b]edit: als ik het AJAX request niet asynchroon doe (false als derder parameter opgeven) dan gedraagt Firefox zich hetzelfde als IE, en voor IE maakt het niet uit. Probleem opgelost! :*)

[ Voor 4% gewijzigd door Bozozo op 03-01-2008 16:35 ]

TabCinema : NiftySplit

Pagina: 1