Lazy loading et appels asynchrones – Une proposition de design pattern

Lorsqu’on programme en POO traditionnelle, c’est souvent une bonne idée de charger les données le plus tard possible, si et quand on en a besoin.
C’est ce qu’on appelle le lazy loading (je ne connais pas le terme en Français et concernant le titre, je n’aime pas le terme patron de conception).

class MyClass
{
    private ABigObject _myVar;
    public ABigObject MyVar
    {
        get
        {
            if(this._myVar == null)
            {
                // Do the needed heavy stuff to retrieve the data here
            }
            return this._myVar;
        }
    }
}

Une des bonnes choses d’Ajax est que cela nous permet de charger des données à la demande. Ce qui est moins bien c’est que la connection HTTP a un coût.
Du coup, être paresseux pour charger les données peut être une bonne idée.

Le problème est que, parce que la connection http peut prendre du temps, on ne veut pas faire d’appel sychrone.

Du coup, le code suivant ne fonctionne pas :

var myObj = {
    myVar:null,
    getMyVar:function(){
    	var that = this;
 
        if(this._myVar == null){
            $.post(
                '/get_my_var.php',
                { },
                function(data){
                    that.myVar = data;
                },
                'json'
            );
        }
        return this.myVar;
    }
 
}

La méthode $.post de JQuery est asychrone. Elle n’attend pas d’avoir terminé pour passer la main au code qui suit.
Donc, lorsque le « return » est exécuté, il y a de bonnes chances que l’appel Ajax ne soit pas terminé et que this.myVar contienne null.

La première approche naïve peut être d’essayer de force l’appel ajax à se comporter comme s’il était synchrone. On peut être tenté de placer un timer avant le return pour laisser le temps à l’appel Ajax de se conclure.
Ceci est, bien sûr, une très mauvaise idée

  • Vous ne pouvez pas être certain que les données sont chargées lorsque le return est appelé. Peut être que votre utilisateur partage avec 100 personnes une connection 56K
  • Afin d’augmenter les chances d’avoir la variable chargée à temps, on est contraint de surestimer le délai d’attente, ce qui implique perdre du temp.
  • Vos utilisateurs ne veulent pas attendre !

Pour résumé, les appels ajax sont asychrones pour une bonne raison.

Conclusion: Il n’est juste pas possible de copier/coller notre design pattern du code C# ci-dessus.

Ce n’est probablement pas la solution ultime mais voici ce à quoi je suis arrivé:

var myObj = {
	myVar:null,
	doWithMyVar:function(callback){
		callback = callback || function(){	};
 
		$.post(
			'/get_my_var.php',
			{	},
			function(data){
				that.myVar = data;
				callback(that.myVar);
			},
			'json'
		);
	}
};
 
// To echo my var:
myObj.doWithMyVar(function(var){ alert(var);	});

En gros, on renverse le processus. Au lieu d’appeler une fonction pour charger les données et d’éxécuter du code avec son résultat, on passe à la fonction qui charge les données le code à éxéctuer avec.

Bien sûr, des solutions plus élégantes sont plus que bienvenues.

    • guillaume bataille
    • 6 octobre 2009

    jamais pris le temps de voir comment est codé le keepalive ajax en général mais c’est rigolo de voir comment tu t’y prends :)

  1. Aucun trackback pour l'instant