Opera et XMLHttpRequest

Le navigateur Opera me surprend souvent par ses implémentations des standards web ; généralement en avance par rapports aux autres constructeurs ; toujours respectueux des dits standards. D'où mon étonnement lorsque j'ai corrigé dans ma librairie javascript un bug qui le touchait et relatif à l'écoute des événements de l'objet XMLHttpRequest...

Dans le document de travail XMLHttpRequest 2, définissant l'objet de requête XMLHttpRequest, il est fait mention de l'interface XMLHttpRequestEventTarget qui étend EventTarget, l'interface DOM mettant à disposition - entre autre - la méthode d'attache d'écouteur d'événement addEventListener ; elle définit par ailleurs les évéments émis : loadstart, progress, abort, error, load, timeout et loadend. On devrait donc s'attendre à pouvoir écrire quelque chose comme ce qui suit(1) :

var request = new XMLHttpRequest();
request.addEventListener('load', function (e) {
    console.log('loaded...');
});
request.send(uri);
Ecoute du chargement d'une ressource par un objet XMLHttpRequest.

En fait, Opera n'a pas (encore) implémenté l'interface EventTarget sur ces objets XMLHttpRequest, ce qui peut d'ailleurs apparaître paradoxal vu que le rédacteur des documents W3C est Anne van Kesteren, employé chez… Opera.

Pour contourner le problème, tout en évitant de modifier le code partout où on utilise XMLHttpRequest, on peut écrire un « encapsuleur » portant un correctif (qui existe déjà le plus souvent, afin de supporter les navigateurs qui ne connaissent pas encore XMLHttpRequest), ce qui donnerait quelque chose du genre :

var XHR = window.XMLHttpRequest.prototype.addEventListener ?
    function () {
        var req = new XMLHttpRequest();
        req.LISTENERS = {};
        req.onreadystatechange = function (e) {
            switch (this.readyState) {
                case 1: 
                    break;
                case 2: 
                    break;
                case 3:
                    if (this.LISTENERS.progress) {
                        this.LISTENERS.progress(e);
                    }
                    break;
                case 4: 
                    if (this.LISTENERS.load) {
                        this.LISTENERS.load(e);
                    }
                break;     
        };
        req.addEventListener = function (event, listener) {
            this.LISTENERS[event] = listener;                
        };
        return req;
    } : function () {
        return new XMLHttpRequest();
    };
Ajout de la méthode addEventListener sur l'objet XMLHttpRequest.
var request = new XHR();
request.addEventListener('load', function (e) {
    console.log('loaded...');
});
request.send(uri);
Utilisation du nouvel objet XHR.
Titre
XHR (XMLHttpRequest / Ajax) support in Opera Presto 2.10
Auteurs
  • Opera
Éditeur
opera.com
Titre
Document Object Model (DOM) Level 3 Events Specification
chapter
4.3 Interface EventTarget
Auteurs
  • Doug Schepers
  • Björn Höhrmann
  • Philippe Le Hégaret
  • Tom Pixley
Éditeur
W3C
Date
Titre
XMLHttpRequest
Auteurs
  • Anne van Kesteren
Éditeur
W3C
Date
Titre
XMLHttpRequest Level 2
Auteurs
  • Anne van Kesteren
Éditeur
W3C
Date
Titre
XMLHttpRequest
Éditeur
MDN
Titre
Using XMLHttpRequest
Éditeur
MDN