The theory and practical course of Javascript bridging mode

Source: Internet
Author: User
Tags flush

The

basic theory

Bridging mode definition: separates the abstract part from its implementation so that they can all change independently. The
Bridging mode consists of 4 main roles:
(1) abstract class
(2) expands the abstract class
(3) Implements the class interface
(4) Implementing classes
based on the characteristics of the JavaScript language, we simplified it to 2 roles:
(1) extending the abstract class
(2) Concrete implementation class
How do you understand bridging mode? We then illustrate the idea of

bridging mode

Understanding bridging patterns, and the key is to understand the idea of separating the abstract and implementing parts. Let's illustrate the illustration


The simplest bridging mode

In fact, our most often used jquery each function is a typical bridging mode, we simulate its implementation as follows:

var each = function (arr, fn) {
for (var i = 0; i < arr.length; i++) {
var val = arr[i];
if (Fn.call (Val, I, Val, arr)) {
return false;
}
}
}
var arr = [1, 2, 3, 4];
Each (arr, function (i, v) {
Arr[i] = v * 2;
})

In this example, we loop through each function arr array, although this example is very common, but it contains a typical bridge mode.

In this example, the abstract part is the each function, which is the extended abstract class above, and the implementation part is FN, that is, the concrete implementation class. The abstract part and the implementation part can be changed independently. Although this example is simple, it is a typical application of bridging mode.




Bridging mode in plug-in development





One applicable scenario for bridging mode is component development. We usually develop components in order to adapt to different occasions, components corresponding to a number of different dimensions of the changes. Bridging mode can be applied to this, separating its abstraction from the implementation, making the component more scalable.


Let's say we want to develop a window widget, the window has different types: Ordinary message reminders, error reminders, each reminder is not the same way to display. This is a typical multidimensional variation of the scene. First we define two classes: the normal message window and the error message window.





function Messagedialog (animation) {


This.animation = animation;


}


MessageDialog.prototype.show = function () {


This.animation.show ();


}


function Errordialog (animation) {


This.animation = animation;


}


ErrorDialog.prototype.show = function () {


This.animation.show ();


}





These two classes are the abstract parts mentioned earlier, that is, the extended abstract class, which contains a member animation.





Both types of Windows are displayed through the Show method, but the animation effects are different. We define two types of effects that are displayed:





function Lineranimation () {


}


LinerAnimation.prototype.show = function () {


Console.log ("It is liner");


}


function Easeanimation () {


}


EaseAnimation.prototype.show = function () {


Console.log ("It is ease");


}





These two classes are specific implementation classes that implement specific display effects. So how do we call it?





var message = new Messagedialog (new Lineranimation ());


Message.show ();


var error = new Errordialog (new Easeanimation ());


Error.show ();





If we want to add an animation effect, you can define an effect class and pass it in.





Summarize





The key to learning bridging mode is to understand the separation between the abstract part and the realization part, so that the two can be changed independently, and not rigidly adhere to the form. JS plug-in flexible changes, the application of the changeable scene is very suitable for the use of this model to achieve. The most important thing to use in bridging mode is to find the different dimensions of the changes in the system.











deep understanding of the bridging pattern of JavaScript design patterns





Bridge mode is most commonly used in event monitoring, read a piece of code first:





Addevent (element, ' click ', Getbeerbyid);


function Getbeerbyid (e) {


var id = this.id;


Asyncrequest (' Get ', ' beer.uri?id= ' + ID, function (RESP) {


Callback Response.


Console.log (' Requested Beer: ' + resp.responsetext);


});


}





The above code, there is a problem is that Getbeerbyid must have the context of the browser to use, because the internal use of This.id this property, if no context, then the rest of the dish. Therefore, a slightly more experienced programmer will change the program into the following form:





function Getbeerbyid (ID, callback) {


Send the request by ID and return the data


Asyncrequest (' Get ', ' beer.uri?id= ' + ID, function (RESP) {


Callback response


Callback (Resp.responsetext);


});


}





It's more practical, isn't it? First, IDs can be passed in randomly, and a callback function is provided to customize the handler function. But what does this have to do with bridging? That's what the next piece of code is going to show:





Addevent (element, ' click ', Getbeerbyidbridge);


function Getbeerbyidbridge (e) {


Getbeerbyid (this.id, function (beer) {


Console.log (' Requested Beer: ' +beer);


});


}





The Getbeerbyidbridge here is the bridge we define to connect the abstract click event with the Getbeerbyid, and the ID of the event source, and a custom call function (Console.log output) is passed into the Getbeerbyid function as a parameter.





This example looks a little bit simpler, so let's take a more complex example of combat.


Combat XHR Connection Queue

We're going to build a queue in which there are many Ajax requests, and queues are used primarily to ensure that first-joined requests are processed first. At any time, we can pause requests, delete requests, retry requests, and support subscription events for individual requests.




Basic core Functions





Before we begin formally, we define a few of the core encapsulation functions, first, the function encapsulation of the asynchronous request:





var asyncrequest = (function () {


function Handlereadystate (o, callback) {


var poll = Window.setinterval (


function () {


if (o &amp;&amp; o.readystate = 4) {


Window.clearinterval (poll);


if (callback) {


Callback (O);


}


}


},


50


);


}





var getxhr = function () {


var http;


try {


http = new XMLHttpRequest;


GETXHR = function () {


return to new XMLHttpRequest;


};


}





catch (e) {


var MSXML = [


' MSXML2. xmlhttp.3.0 ',


' MSXML2. XMLHTTP ',


' Microsoft.XMLHTTP '


];





for (var i = 0, len = msxml.length i &lt; len; ++i) {


try {


http = new ActiveXObject (Msxml[i]);


GETXHR = function () {


return new ActiveXObject (Msxml[i]);


};


Break


}


catch (e) {}


}


}


return HTTP;


};





return function (method, Uri, callback, PostData) {


var http = getxhr ();


Http.open (method, Uri, true);


Handlereadystate (HTTP, callback);


Http.send (PostData | | null);


return HTTP;


};


})();





The encapsulated self execution function is a general-purpose AJAX request function that people who believe in attribute Ajax can read.





Next we define a common way to add a method (function):





Function.prototype.method = function (name, FN) {


This.prototype[name] = fn;


return this;


};





Finally, add 2 methods for the array, one for traversal and one for filtering:





if (! Array.prototype.forEach) {


Array.method (' ForEach ', function (FN, thisobj) {


var scope = Thisobj | | Window


for (var i = 0, len = this.length i &lt; len; ++i) {


Fn.call (scope, this[i], I, this);


}


});


}





if (! Array.prototype.filter) {


Array.method (' Filter ', function (FN, thisobj) {


var scope = Thisobj | | Window


var a = [];


for (var i = 0, len = this.length i &lt; len; ++i) {


if (!fn.call (scope, this[i], I, this)) {


Continue


}


A.push (This[i]);


}


return A;


});


}





Because some new browsers already support these two functions (or some libraries have already been supported), they should be judged first, and if they are already supported, they will not be processed.




Observer System





The observer plays an important role in the event process in the queue, and can subscribe to events when the queue is processed (successful, failed, pending):





Window. DED = window. DED | | {};


Ded.util = Ded.util | | {};


DED.util.Observer = function () {


This.fns = [];


}





DED.util.Observer.prototype = {


Subscribe:function (FN) {


This.fns.push (FN);


},





Unsubscribe:function (FN) {


This.fns = This.fns.filter (


Function (EL) {


If (El!== fn) {


Return el;


}


}


);


},


Fire:function (o) {


This.fns.forEach (


Function (EL) {


El (O);


}


);


}


};





Queue Main Implementation Code





First subscribe to the main attributes and event delegates for the queue:





DED. Queue = function () {


The queue that contains the request.


This.queue = [];


Use the observable object in 3 different states so that you can subscribe to events at any time


This.oncomplete = new DED.util.Observer;


This.onfailure = new DED.util.Observer;


This.onflush = new DED.util.Observer;





Core properties, which can be set when external calls are made


This.retrycount = 3;


this.currentretry = 0;


this.paused = false;


This.timeout = 5000;


This.conn = {};


This.timer = {};


};





Then, with the DED.Queue.method chain call, many of the available methods are added to the queue:





DED. Queue.


Method (' Flush ', function () {


Flush method


if (!this.queue.length &gt; 0) {


Return


}





if (this.paused) {


this.paused = false;


Return


}





var that = this;


this.currentretry++;


var abort = function () {


That.conn.abort ();


if (that.currentretry = = That.retrycount) {


That.onFailure.fire ();


that.currentretry = 0;


} else {


That.flush ();


}


};





This.timer = Window.settimeout (abort, this.timeout);


var callback = function (o) {


Window.cleartimeout (That.timer);


that.currentretry = 0;


That.queue.shift ();


That.onFlush.fire (O.responsetext);


if (That.queue.length = = 0) {


That.onComplete.fire ();


Return


}





Recursive call to Flush


That.flush ();





};





This.conn = Asyncrequest (


This.queue[0][' method '],


this.queue[0][' URI '],


Callback


this.queue[0][' params ']


);


}).


Method (' Setretrycount ', function (count) {


This.retrycount = count;


}).


Method (' SetTimeout ', function (time) {


This.timeout = time;


}).


Method (' Add ', function (o) {


This.queue.push (o);


}).


Method (' Pause ', function () {


This.paused = true;


}).


Method (' Dequeue ', function () {


This.queue.pop ();


}).


Method (' Clear ', function () {


This.queue = [];


});





The code looks a lot, folded to find, in fact, is defined on the queue flush, Setretrycount, settimeout, add, pause, dequeue, and clear methods.




Simple Call





var q = new DED. Queue;


Set a higher number of retries to cope with slow connections


Q.setretrycount (5);


Set timeout time


Q.settimeout (1000);


Added 2 requests.


Q.add ({


Method: ' Get ',


URI: '/path/to/file.php?ajax=true '


});





Q.add ({


Method: ' Get ',


URI: '/path/to/file.php?ajax=true&amp;woe=me '


});





Flush queues


Q.flush ();


Pause queue, remaining save


Q.pause ();


Empty.


Q.clear ();


Added 2 requests.


Q.add ({


Method: ' Get ',


URI: '/path/to/file.php?ajax=true '


});





Q.add ({


Method: ' Get ',


URI: '/path/to/file.php?ajax=true&amp;woe=me '


});





Deletes the last request from the queue.


Q.dequeue ();


Flush again


Q.flush ();





What about the bridge?





There is no bridge in the calling code above, what about the bridge? Take a look at the complete example below and you'll find bridges everywhere:





&lt;! DOCTYPE HTML PUBLIC "-//w3c//dtd HTML 4.01//en"


"Http://www.w3.org/TR/html4/strict.dtd" &gt;


&lt;html&gt;


&lt;head&gt;


&lt;meta http-equiv= "Content-type" content= "text/html; Charset=utf-8 "&gt;


&lt;title&gt;ajax Connection queue&lt;/title&gt;


&lt;script src= "Utils.js" &gt;&lt;/script&gt;


&lt;script src= "Queue.js" &gt;&lt;/script&gt;


&lt;script type= "Text/javascript" &gt;


addevent (window, ' Load ', function () {


Realize.


var q = new DED. Queue;


Q.setretrycount (5);


Q.settimeout (3000);


var items = $ (' items ');


var results = $ (' results ');


var queue = $ (' queue-items ');


Keep track of your requests on the client


var requests = [];


Subscribe to special processing steps after each request flush


Q.onflush.subscribe (function (data) {


results.innerhtml = data;


Requests.shift ();


queue.innerhtml = Requests.tostring ();


});


Subscription time processing steps


Q.onfailure.subscribe (function () {


results.innerhtml = ' &lt;span style= ' color:red; &gt;connection error!&lt;/span&gt; ';


});


Subscribe to all successful processing steps x


Q.oncomplete.subscribe (function () {


results.innerhtml = ' &lt;span style= ' color:green; &gt;Completed!&lt;/span&gt; ';


});


var actiondispatcher = function (Element) {


Switch (Element) {


Case ' flush ':


Q.flush ();


Break


Case ' dequeue ':


Q.dequeue ();


Requests.pop ();


queue.innerhtml = Requests.tostring ();


Break


Case ' pause ':


Q.pause ();


Break


Case ' Clear ':


Q.clear ();


requests = [];


queue.innerhtml = ';


Break


}


};


var addrequest = function (Request) {


var data = Request.split ('-') [1];


Q.add ({


Method: ' Get ',


URI: ' bridge-connection-queue.php?ajax=true&amp;s= ' + data,


Params:null


});


Requests.push (data);


queue.innerhtml = Requests.tostring ();


};


Addevent (items, ' click ', Function (e) {


var e = e | | window.event;


var src = E.target | | E.srcelement;


try {


E.preventdefault ();


}


catch (ex) {


E.returnvalue = false;


}


Actiondispatcher (src.id);


});


var adders = $ (' adders ');


Addevent (adders, ' click ', Function (e) {


var e = e | | window.event;


var src = E.target | | E.srcelement;


try {


E.preventdefault ();


}


catch (ex) {


E.returnvalue = false;


}


Addrequest (src.id);


});


});


&lt;/script&gt;


&lt;style type= "text/css" media= "screen" &gt;


Body


{


font:100% Georgia,times,serif;


}


H1, H2


{


Font-weight:normal;


}


#queue-items


{


Height:1.5em;


}


#add-stuff


{


padding:. 5em;


Background: #ddd;


border:1px solid #bbb;


}


#results-area


{


padding:. 5em;


border:1px solid #bbb;


}


&lt;/style&gt;


&lt;/head&gt;


&lt;body id= "Example" &gt;


&lt;div id= "Doc" &gt;


&lt;h1&gt;


Asynchronous join Request &lt;/h1&gt;


&lt;div id= "Queue-items" &gt;


&lt;/div&gt;


&lt;div id= "Add-stuff" &gt;


&lt;h2&gt; add a new request to the queue &lt;/h2&gt;


&lt;ul id= "Adders" &gt;


&lt;li&gt;&lt;a href= "#" id= "action-01" &gt; Add "01" to queue &lt;/a&gt;&lt;/li&gt;


&lt;li&gt;&lt;a href= "#" id= "action-02" &gt; Add "02" to queue &lt;/a&gt;&lt;/li&gt;


&lt;li&gt;&lt;a href= "#" id= "action-03" &gt; Add "03" to queue &lt;/a&gt;&lt;/li&gt;


&lt;/ul&gt;


&lt;/div&gt;


&lt;h2&gt; Queue Control &lt;/h2&gt;


&lt;ul id= ' Items ' &gt;


&lt;li&gt;&lt;a href= "#" id= "Flush" &gt;Flush&lt;/a&gt;&lt;/li&gt;


&lt;li&gt;&lt;a href= "#" id= "Dequeue" &gt; Out dequeue&lt;/a&gt;&lt;/li&gt;


&lt;li&gt;&lt;a href= "#" id= "pause" &gt; Suspend pause&lt;/a&gt;&lt;/li&gt;


&lt;li&gt;&lt;a href= "#" id= "clear" &gt; Empty clear&lt;/a&gt;&lt;/li&gt;


&lt;/ul&gt;


&lt;div id= "Results-area" &gt;


&lt;h2&gt;


Results:


&lt;/h2&gt;


&lt;div id= "Results" &gt;


&lt;/div&gt;


&lt;/div&gt;


&lt;/div&gt;


&lt;/body&gt;


&lt;/html&gt;





In this example, you can do flush queues, pause queues, delete requests in queues, empty queues, and so on, and believe that you also feel the power of bridging.





Summary





The advantages of bridging mode are also obvious, and we only cite a few main advantages:





Separating the interface from the implementation part, an implementation is not necessarily bound to an interface, abstract class (function) implementation can be configured at runtime, an object can even change its implementation at runtime, with the abstraction and implementation of the full decoupling, but also conducive to layering, resulting in a better structured system.


Increase scalability


Implementation details are transparent to the customer and can hide implementation details from the customer.





Bridge mode also has its own disadvantages:





A large number of classes will lead to an increase in development costs and may also decrease in performance.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.