passage d’object à la fonction de rappel dans jQuery

Je travaille récemment sur un petit module de discussion en ligne, qui nécessite une vérification continue du serveur pour détecter tout nouveau message.

J’envoie une demande ajax à un serveur, et le serveur conserve la connexion jusqu’à ce qu’un nouveau message soit trouvé (longue interrogation).

Code:

var chatController = function(){ //other variable declaration /** * Ajax call to monitor the new message , on complete of ajax call sending other call */ this.checkNewMessage = function(){ console.log(this); // placed this for debugging purpose $.ajax({ url : SITEURL.CHECK_MESSAGE, data : this.currrentUserDetails, dataType : 'json' , cache : false, success :(function(obj){ //temp = obj; return obj.parseNewMessageResponse; })(this), complete: (function(obj){ //temp = obj; return obj.checkNewMessage; })(this), }); }; // other function and variable }); 

Quand j’ai essayé d’appeler

 var mainController = new chatController(); mainController.checkNewMessage(); 

Problème

Ce que je pensais, c’est que je serais capable d’envoyer une demande unique continue au serveur, mais à ma grande surprise, je ne pouvais envoyer que 2 demandes ajax l’une après l’autre.

Mon débogage

Quand j’ai essayé de déboguer, j’ai découvert que pour le premier appel, this object étant transmis chatController vers le chatController

  complete: (function(obj){ return obj.checkNewMessage; })(this), // this here point to chatController object 

Pour la deuxième fois, this object transmis pointe sur l’ ajax object

  complete: (function(obj){ return obj.checkNewMessage; })(this), // this here point to ajax object 

J’utilise la fermeture JavaScript pour transmettre l’object chatController afin de complete paramètre de jquery

Donc, ce que je veux, c’est un moyen de passer un paramètre à la fonction complete jQuery afin qu’il pointe vers ma référence d’origine

Il existe différentes solutions multi-navigateurs possibles

Vous pouvez utiliser $.proxy :

À mon avis, la meilleure pratique.

 $.ajax({ //... success: $.proxy(function(json) { // `this` refers to the second argument of `$.proxy` }, this) }); 

Vous pouvez définir l’ option de context :

 $.ajax({ //... context: this, success: function(json) { // `this` refers to the value of `context` } }); 

Ou utilisez une fermeture :

 var self = this; $.ajax({ //... success: function(json) { // `this` refers to ajax request, use self instead $(self).dosomething(); } }); 

Le moyen le plus simple de résoudre ce problème consiste à définir une référence à votre nom d’origine afin que vous puissiez y accéder depuis un autre contexte. Vérifiez cet exemple simple:

 (function(){ var _self = this; function changeColor($element, color){ $element.css("background-color", color) } $(".recolor-btn").click(function(){ var self = this; $.ajax({ url: "/Color/GetRandom", success: function(color){ _self.changeColor($(self), color); } }); }); })(); 

Il existe au moins quatre manières différentes de résoudre le problème de ne pas appeler votre méthode avec le bon contexte, à partir de votre success et de vos gestionnaires complete .

  1. Utilisez l’argument context de $.ajax() pour que this dans votre gestionnaire de succès ce que vous voulez, afin que vous puissiez ensuite appeler votre méthode.

  2. Utilisez .bind() pour créer un nouveau stub de fonction qui appelle votre méthode avec le bon contexte.

  3. Enregistrez sa valeur dans une variable locale afin de pouvoir la référencer lorsque vous en avez besoin dans une fonction de stub.

  4. Utilisez la version .bind() de .bind() de .bind() appelée $.proxy() .

Je vais vous offrir quelques exemples de chacun.

Premièrement, l’option de context pour $.ajax() :

 this.checkNewMessage = function(){ console.log(this); // placed this for debugging purpose $.ajax({ context: this, url : SITEURL.CHECK_MESSAGE, data : this.currrentUserDetails, dataType : 'json' , cache : false, success : function(data) { this.parseNewMessageResponse(data); }, complete : function(data) { this.checkNewMessage(); } }); }; 

Ensuite, utilisez .bind() .

 this.checkNewMessage = function(){ console.log(this); // placed this for debugging purpose $.ajax({ url : SITEURL.CHECK_MESSAGE, data : this.currrentUserDetails, dataType : 'json' , cache : false, success : this.parseNewMessageResponse.bind(this), complete : this.checkNewMessage.bind(this) }); }; 

Ensuite, en utilisant une copie sauvegardée de this :

 this.checkNewMessage = function(){ var self = this; console.log(this); // placed this for debugging purpose $.ajax({ url : SITEURL.CHECK_MESSAGE, data : this.currrentUserDetails, dataType : 'json' , cache : false, success : function(data) { self.parseNewMessageResponse(data); }, complete : function(data) { self.checkNewMessage(); } }); }; 

Et enfin avec `.proxy ():

 this.checkNewMessage = function(){ console.log(this); // placed this for debugging purpose $.ajax({ url : SITEURL.CHECK_MESSAGE, data : this.currrentUserDetails, dataType : 'json' , cache : false, success : $.proxy(this.parseNewMessageResponse, this), complete : $.proxy(this.checkNewMessage, this) }); }; 

Si vous n’avez pas besoin de la prise en charge d’IE8 ou si vous ne voulez pas installer un polyfill pour .bind() , l’option .bind() est ma préférée, car elle semble tout simplement la plus propre.