introduire
Le mode de pont sépare les pièces abstraites de ses pièces d'implémentation afin qu'elles puissent toutes varier indépendamment.
texte
Le mode de pont est le plus souvent utilisé dans la surveillance des événements. Regardons d'abord un morceau de code:
La copie de code est la suivante:
addEvent (élément, 'click', getbeerbyid);
fonction getbeerbyid (e) {
var id = this.id;
asyncrequest ('get', 'bier.uri? id =' + id, fonction (resp) {
// Réponse de rappel.
Console.log ('Bière demandée:' + resp.ResponSeText);
});
}
Il y a un problème avec le code ci-dessus que GetBeerByid doit avoir un contexte de navigateur à utiliser, car il utilise cette propriété. Si le contexte n'est pas utilisé, ce sera un arrêt. Par conséquent, généralement un programmeur peu expérimenté transformera le programme en la forme suivante:
La copie de code est la suivante:
function getBeerByid (id, rappel) {
// Envoyez la demande par ID et renvoyez les données
asyncrequest ('get', 'bier.uri? id =' + id, fonction (resp) {
// Réponse de rappel
rappel (resp.ResponSeText);
});
}
Plus pratique, non? Tout d'abord, l'ID peut être transmis à volonté et une fonction de rappel est également fournie pour les fonctions de traitement personnalisées. Mais qu'est-ce que cela a à voir avec le pontage? C'est ce que le code suivant va refléter:
La copie de code est la suivante:
addEvent (élément, 'click', getbeerbyidbridge);
fonction getbeerbyidbridge (e) {
getbeerbyid (this.id, fonction (bière) {
Console.log ('Bière demandée:' + bière);
});
}
Ici, GetBeerByIdBridge est le pont que nous définissons, qui est utilisé pour connecter l'événement de clic abstrait et GetBeerByid, et en même temps passer l'ID de la source de l'événement et la fonction d'appel personnalisée (sortie Console.log) dans la fonction GetBeerByid comme paramètres.
Cet exemple semble un peu simple, prenons un autre exemple pratique plus compliqué.
File d'attente de connexion XHR réelle
Nous voulons construire une file d'attente, qui stocke de nombreuses demandes AJAX dans la file d'attente. L'utilisation des files d'attente est principalement due au fait que nous devons nous assurer que les demandes réunies sont d'abord traitées. À tout moment, nous pouvons interrompre les demandes, supprimer les demandes, réessayer les demandes et prendre en charge les événements d'abonnement pour chaque demande.
Fonctions de base de base
Avant le départ officiel, définissons plusieurs fonctions d'encapsulation de base. Premièrement, le premier est l'encapsulation de la fonction des demandes asynchrones:
La copie de code est la suivante:
var asyncrequest = (function () {
Fonction HandleReadyState (o, rappel) {
var poll = window.setinterval (
fonction () {
if (o && o.readystate == 4) {
Window.ClearInterval (Sondage);
if (rappel) {
rappel (o);
}
}
},
50
));
}
var getxhr = fonction () {
var http;
essayer {
http = new xmlHttpRequest;
getXhr = function () {
Renvoie un nouveau XMLHTTPREQUEST;
};
}
catch (e) {
var msxml = [
'Msxml2.xmlhttp.3.0',
«Msxml2.xmlhttp»,
'Microsoft.xmlhttp'
]]
pour (var i = 0, len = msxml.length; i <len; ++ i) {
essayer {
http = new activeXObject (msxml [i]);
getXhr = function () {
return new activeXObject (msxml [i]);
};
casser;
}
catch (e) {}
}
}
retour http;
};
Fonction de retour (méthode, uri, rappel, postdata) {
var http = getXhr ();
http.open (méthode, uri, true);
HandleReadyState (HTTP, rappel);
http.send (postdata || null);
retour http;
};
}) ();
La fonction auto-exécutée encapsulée est une fonction de demande générale de l'AJAX, et je crois que toute personne ayant l'attribut AJAX peut la comprendre.
Ensuite, nous définissons une méthode générale pour ajouter des méthodes (fonctions):
La copie de code est la suivante:
Function.prototype.method = function (name, fn) {
this.prototype [name] = fn;
retourner ceci;
};
Enfin, ajoutez 2 méthodes sur les tableaux, un pour la traversée et un pour le filtrage:
La copie de code est la suivante:
if (! array.prototype.ForEach) {
Array.method ('foreach', fonction (fn, thisObj) {
var scope = thisObj || fenêtre;
pour (var i = 0, len = this.length; i <len; ++ i) {
fn.Call (Scope, this [i], i, this);
}
});
}
if (! array.prototype.filter) {
Array.method ('filter', fonction (fn, thisObj) {
var scope = thisObj || fenêtre;
var a = [];
pour (var i = 0, len = this.length; i <len; ++ i) {
if (! fn.call (scope, this [i], i, this)) {
continuer;
}
a.push (this [i]);
}
retourner a;
});
}
Étant donné que certains nouveaux navigateurs soutiennent déjà ces deux fonctions (ou certaines bibliothèques de classe les soutiennent déjà), nous devons d'abord juger s'ils sont déjà pris en charge, et s'ils sont déjà pris en charge, ils ne seront plus traités.
Système d'observateur
Les observateurs jouent un rôle important dans le processus d'événements dans la file d'attente et peuvent s'abonner aux événements lorsqu'ils sont en file d'attente (succès, échec, en attente):
La copie de code est la suivante:
window.ded = window.ded || {};
Ded.util = ded.util || {};
Ded.util.observer = function () {
this.fns = [];
}
Ded.util.observer.prototype = {
abonnez-vous: fonction (fn) {
this.fns.push (fn);
},
désinscriptif: fonction (fn) {
this.fns = this.fns.filter (
fonction (el) {
if (el! == fn) {
Retour El;
}
}
));
},
Feu: fonction (o) {
this.fns.Forach (
fonction (el) {
el (o);
}
));
}
};
Le principal code d'implémentation de file d'attente
Tout d'abord, vous vous abonnez aux principaux attributs et délégués d'événements de la file d'attente:
La copie de code est la suivante:
Ded.Queue = function () {
// contient la file d'attente pour les demandes.
this.queue = [];
// Utilisez un objet observable sur 3 états différents afin que vous puissiez vous abonner à des événements à tout moment
this.onComplete = new ded.util.observer;
this.onfailure = new ded.util.observer;
this.onflush = new ded.util.observer;
// Les propriétés centrales peuvent être définies lors d'appels externes
this.retryCount = 3;
this.currenTretry = 0;
this.paused = false;
this.timeout = 5000;
this.conn = {};
this.timer = {};
};
Ensuite, grâce à l'appel enchaîné de Ded.Queue.Method, de nombreuses méthodes disponibles sont ajoutées à la file d'attente:
La copie de code est la suivante:
Ded.Queue.
méthode ('flush', function () {
// Méthode de rinçage
if (! this.queue.length> 0) {
retour;
}
if (this.paused) {
this.paused = false;
retour;
}
var that = this;
this.currenTretry ++;
var abort = function () {
that.conn.abort ();
if (that.currenTretry == that.retryCount) {
that.onfailure.fire ();
that.currenTretry = 0;
} autre {
that.flush ();
}
};
this.timer = window.setTimeout (aborter, this.timeout);
var callback = fonction (o) {
window.cleartimeout (that.timer);
that.currenTretry = 0;
that.queue.shift ();
that.onflush.fire (O.ResponSeText);
if (that.queue.length == 0) {
that.oncompte.fire ();
retour;
}
// Appel récursif à rincer
that.flush ();
};
this.conn = asyncrequest (
this.queue [0] ['méthode'],
this.queue [0] ['uri'],
rappel,
this.queue [0] ['params']
));
}).
Méthode ('setRetryCount', fonction (count) {
this.retryCount = count;
}).
méthode ('setTimeout', fonction (time) {
this.timeout = time;
}).
méthode ('add', fonction (o) {
this.queue.push (o);
}).
méthode ('pause', fonction () {
this.paused = true;
}).
Méthode ('Dequeue', fonction () {
this.queue.pop ();
}).
méthode ('clear', function () {
this.queue = [];
});
Le code semble beaucoup, et après le pliage, vous pouvez constater qu'il est réellement défini dans la file d'attente avec Flush, SetRetryCount, Settimeout, Add, Pause, Dequeue et Clear Methods.
Appel simple
La copie de code est la suivante:
var q = new ded.Queue;
// Définit le nombre de réessiers un peu plus élevés pour faire face aux connexions lentes
q.setRetryCount (5);
// définir le temps de temps
Q.SetTimeout (1000);
// Ajouter 2 demandes.
q.add ({
Méthode: «Get»,
uri: '/path/to/file.php?ajax=true'
});
q.add ({
Méthode: «Get»,
uri: '/path/to/file.php?ajax=true&woe=me'
});
// Fesure de la file d'attente
q.flush ();
// suscite la file d'attente et enregistrer les autres
Q.Pause ();
// Clair.
Q.Clear ();
// Ajouter 2 demandes.
q.add ({
Méthode: «Get»,
uri: '/path/to/file.php?ajax=true'
});
q.add ({
Méthode: «Get»,
uri: '/path/to/file.php?ajax=true&woe=me'
});
// supprime la dernière demande de la file d'attente.
q.dequeue ();
// rincer à nouveau
q.flush ();
Où est le pont?
Il n'y a pas de pont dans le code d'appel ci-dessus, alors qu'en est-il du pont? Jetez un œil à l'exemple complet ci-dessous et vous constaterez qu'il y a des ponts partout:
La copie de code est la suivante:
<! Doctype html public "- // w3c // dtd html 4.01 // en"
"http://www.w3.org/tr/html4/strict.dtd">
<html>
<adal>
<meta http-equiv = "contenu-type" contenu = "text / html; charset = utf-8">
<Title> Ajax Connection Queue </TITME>
<script src = "utils.js"> </ script>
<script src = "queue.js"> </ script>
<script type = "text / javascript">
addEvent (fenêtre, 'charger', function () {
// accomplir.
var q = new ded.Queue;
q.setRetryCount (5);
Q.SetTimeout (3000);
var items = $ ('items');
var résultats = $ («résultats»);
var queue = $ («file d'attente»);
// Enregistrez sur suivi votre demande sur le client
var requêtes = [];
// Après chaque demande de chasse, abonnez-vous à des étapes de traitement spéciales
q.onflush.subscribe (fonction (data) {
résultats.innerhtml = données;
requêtes.shift ();
queue.innerhtml = requêtes.toString ();
});
// étapes de traitement du temps d'abonnement
q.onfailure.subscribe (function () {
résultats.innerhtml + = '<span style = "Color: Red;"> Erreur de connexion! </span>';
});
// Abonnez-vous à toutes les étapes de traitement réussies x
q.oncompte.subscribe (function () {
résultats.innerhtml + = '<span style = "couleur: vert;"> terminé! </span>';
});
var actionDispatcher = fonction (élément) {
commutateur (élément) {
case «rince»:
q.flush ();
casser;
Cas «Dequeue»:
q.dequeue ();
requêtes.pop ();
queue.innerhtml = requêtes.toString ();
casser;
cas «pause»:
Q.Pause ();
casser;
cas «clair»:
Q.Clear ();
requêtes = [];
queue.innerhtml = '';
casser;
}
};
var addRequest = function (request) {
var data = request.split ('-') [1];
q.add ({
Méthode: «Get»,
uri: 'pont-connection-queue.php? ajax = true & s =' + data,
Params: null
});
remanes.push (data);
queue.innerhtml = requêtes.toString ();
};
addEvent (éléments, 'click', fonction (e) {
var e = e || window.event;
var src = e.target || e.srcelement;
essayer {
E.PreventDefault ();
}
catch (ex) {
e.reTurnValue = false;
}
ActionDispatcher (src.id);
});
var adders = $ ('adders');
addEvent (adders, 'click', fonction (e) {
var e = e || window.event;
var src = e.target || e.srcelement;
essayer {
E.PreventDefault ();
}
catch (ex) {
e.reTurnValue = false;
}
addRequest (src.id);
});
});
</cript>
<style type = "Text / CSS" Media = "Screen">
Corps
{
Police: 100% Géorgie, Times, Serif;
}
H1, H2
{
Police-poids: normal;
}
# que la file d'attente
{
hauteur: 1.5EM;
}
# Add-Stuff
{
rembourrage: .5em;
Contexte: #ddd;
Border: 1px solide #bbb;
}
# Results-Area
{
rembourrage: .5em;
Border: 1px solide #bbb;
}
</ style>
</ head>
<body id = "example">
<div id = "doc">
<h1>
Demande de jointure asynchrone </H1>
<div id = "file d'attente">
</div>
<div id = "add-stuff">
<h2> Ajoutez une nouvelle demande à la file d'attente </h2>
<ul id = "adders">
<li> <a href = "#" id = "Action-01"> Ajouter "01" à la file d'attente </a> </li>
<li> <a href = "#" id = "Action-02"> Ajouter "02" à la file d'attente </a> </li>
<li> <a href = "#" id = "Action-03"> Ajouter "03" à la file d'attente </a> </li>
</ul>
</div>
<h2> Contrôle de la citation </h2>
<ul id = 'items'>
<li> <a href = "#" id = "flush"> flush </a> </li>
<li> <a href = "#" id = "Dequeue"> Dequeue </a> </li>
<li> <a href = "#" id = "pause"> pause </a> </li>
<li> <a href = "#" id = "clear"> Clear </a> </li>
</ul>
<div id = "Results-Area">
<h2>
résultat:
</h2>
<div id = "résultats">
</div>
</div>
</div>
</docy>
</html>
Dans cet exemple, vous pouvez effectuer diverses actions telles que des files d'attente à chasse d'eau, des files d'attente en pause, supprimer les demandes dans les files d'attente, des files d'attente claires, etc. En même temps, je pense que tout le monde a également connu le pouvoir des ponts.
Résumer
Les avantages du mode Bridge sont également évidents. Nous listerons seulement quelques avantages principaux:
1. Séparez les pièces d'interface et d'implémentation. Une implémentation peut ne pas être liée à une interface invariablement. L'implémentation de la classe abstraite (fonction) peut être configurée au moment de l'exécution, et un objet peut même modifier son implémentation lors de l'exécution. Il découple également entièrement l'abstraction et la mise en œuvre, qui est également propice à la superposition, générant ainsi un système mieux structuré.
2. Améliorer l'évolutivité
3. Les détails de l'implémentation sont transparents aux clients et peuvent masquer les détails de l'implémentation des clients.
Dans le même temps, le mode Bridge a également ses propres inconvénients:
Un grand nombre de classes entraîneront une augmentation des coûts de développement et pourraient également réduire les performances.