web-dev-qa-db-fra.com

$ (fenêtre) .unload attendre pour AJAX appeler pour terminer avant de quitter une page Web

Fondamentalement, une fois qu'un utilisateur a laissé une page Web dans mon application, je dois appeler un script PHP avec AJAX, qui insère le temps passé sur la page Web dans la base de données, puis quitte la page.

Il est important d'attendre la fin de la demande AJAX, car les pages Web de mon application ne sont pas accessibles aux utilisateurs, sauf s'ils ont passé un certain temps sur une page précédente (deux minutes, par exemple).

Voici mon code jQuery:

$(document).ready(function() {

    var teid = TEID;
    var startTime = new Date().getTime();

    $(window).unload(function() {
        var timeSpentMilliseconds = new Date().getTime() - startTime;
        var t = timeSpentMilliseconds / 1000 / 60;

        $.ajax({
            type: 'POST',
            url: '/clientarea/utils/record-time',
            data: 'teid=' + teid + '&t=' + t
        });
    });

});

Comment dois-je le modifier pour qu'il attende que la demande AJAX se termine avant de quitter la page Web?

MODIFIER:

Ou il pourrait être préférable (plus facile) de simplement laisser la demande AJAX se répéter toutes les minutes environ. Est-ce possible?

31
Richard Knop

Eh bien, vous pouvez définir async: false sur votre appel AJAX pour que le navigateur attende la fin de la demande avant de faire quoi que ce soit d'autre, mais notez que cela "bloquera" le navigateur pendant toute la durée de la demande.

$.ajax({
    type: 'POST',
    async: false,
    url: '/clientarea/utils/record-time',
    data: 'teid=' + teid + '&t=' + t
});

Du manuel:

Par défaut, toutes les demandes sont envoyées de manière asynchrone (c’est-à-dire que ce paramètre est défini sur true par défaut). Si vous avez besoin de requêtes synchrones, définissez cette option sur false. Les requêtes interdomaines et dataType: Les requêtes "jsonp" ne prennent pas en charge le fonctionnement synchrone. Notez que les requêtes synchrones peuvent verrouiller temporairement le navigateur, ce qui désactive toute action tant que la requête est active.

31
Tatu Ulmanen

La meilleure solution consiste à utiliser navigator.sendBeacon . C'est une toute nouvelle fonctionnalité qui commence à être implémentée dans les nouvelles versions des navigateurs. Cette fonction est disponible dans les navigateurs plus récents que Chrome 39 et Firefox 31. Elle n’est pas prise en charge par Internet Explorer et Safari au moment de la rédaction. Pour vous assurer que votre demande est envoyée dans les navigateurs qui ne prennent pas encore en charge la nouvelle fonctionnalité, vous pouvez utiliser cette solution:

var navigator.sendBeacon = navigator.sendBeacon || function (url, data) {
  var client = new XMLHttpRequest();
  client.open("POST", url, false); // third parameter indicates sync xhr
  client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
  client.send(data);
};

J'espère que cela t'aides! 

7
user1319331

Que diriez-vous de définir un cookie dans le gestionnaire de déchargement? Le serveur devrait le voir sur les demandes suivantes.

<script>
    $(window).unload(function(){document.cookie='left_on='+(new Date())})
</script>
6
Sixtease

pour moi, votre navigateur n’est pas une bonne idée d’attendre avant de fermer ...
tout simplement parce que si je veux vraiment le fermer? ... 

si une page dérange un utilisateur, ce n'est pas bon ...

ma suggestion est, dans la page, vous attendez 2 minutes (si 2 minutes sont les exigences), puis envoyez un ajax que l'utilisateur a fait ses 2 minutes ...

vous pouvez alors le vérifier côté serveur si on a ses 2 minutes ou pas ...

4
Reigel

C'est une mauvaise idée d'essayer de pirater le navigateur de vos utilisateurs, car cela leur donnerait un mauvais pressentiment et les renverrait.

Si, pour une raison quelconque, vous ne souhaitez pas créer de nouvelle page tant que l'utilisateur n'a pas passé un temps minimal sur la précédente, la meilleure chose à faire est de piloter côté serveur, c'est-à-dire de rediriger vers la page en cours jusqu'à ce que le temps demandé soit écoulé.

Vous n'avez même pas besoin de faire d'appels ajax, mais simplement d'enregistrer dans la session l'horodatage du moment où la page a été servie et de ne pas afficher la page suivante jusqu'à ce qu'un certain laps de temps se soit écoulé.

Assurez-vous d'indiquer aux utilisateurs qu'ils doivent attendre qu'une nouvelle page soit prête, peut-être avec un simple compte à rebours javascript.

Si vous voulez que la page soit active pendant un certain temps (par exemple, ne pas passer à un autre onglet/fenêtre en attendant que les deux minutes s'écoulent), je ne peux pas proposer de solution efficace.

2
Iacopo

utiliser onbeforeunload:

$(document).ready(function(){
  window.onbeforeunload = function(){
     // $.ajax stuff here
     return false;
  }
});

Cela apportera au moins à l'utilisateur une messagebox qui lui demande s'il veut fermer la fenêtre/l'onglet en cours.

1
jAndy

Je pense qu'il serait bien préférable d'utiliser une technique d'interrogation comme vous le suggérez, bien que cela provoque une charge sur le serveur Web.

$(document).ready(function() {

    var teid = TEID;
    var startTime = new Date().getTime();

    var ajaxFunc = function() {
        var timeSpentMilliseconds = new Date().getTime() - startTime;
        var t = timeSpentMilliseconds / 1000 / 60;

        $.ajax({
            type: 'POST',
            url: '/clientarea/utils/record-time',
            data: 'teid=' + teid + '&t=' + t
        });
    };

    setInterval(ajaxFunc, 60000);

})

Vous serez heureux quand vous pourrez utiliser les websockets :)

1
sje397

La méthode jQuery.ajax() a l'option async. Si vous le définissez sur false, l'appel sera bloqué jusqu'au retour de la réponse (ou jusqu'à l'expiration du délai). Je suis assez sûr que cet appel appelle le navigateur pour qu’il intègre le gestionnaire de déchargement.

Note latérale: Vous ne pouvez pas compter sur cela pour fonctionner. Si le navigateur donne à l'utilisateur la possibilité d'annuler les gestionnaires de déchargement (ce que font certains navigateurs après un certain délai), le "temps passé sur le site" ne sera jamais mis à jour. Vous pouvez ajouter une minuterie au site, qui appelle périodiquement un script sur le serveur et qui met à jour l'heure. Vous n'aurez pas de valeur exacte, mais dans votre cas, cela n'est pas nécessaire.

Si vous avez seulement besoin de savoir si l'utilisateur est X secondes sur la page, vous pouvez simplement définir un délai d'attente dans le gestionnaire de chargement onload (à l'aide de setTimeout(function, ms)) qui passe un appel si l'utilisateur a passé le temps requis. Il n'y aurait donc pas besoin d'un gestionnaire de déchargement.

0
Martin Thurau