W styczniu tego roku jQuery ogłosił nowy rejestr wtyczek , więc teraz wydawało mi się, że świetnie jest napisać samouczek, łączący tworzenie wtyczki jQuery z moją pasją - technologie sieciowe w czasie rzeczywistym.

Technologie sieciowe w czasie rzeczywistym znacznie ułatwiają dodawanie treści na żywo do wcześniej statycznych stron internetowych. Treści na żywo mogą ożywiać stronę, zatrzymywać użytkowników i usuwać konieczność okresowego odświeżania strony. Aktualizacje w czasie rzeczywistym są generalnie osiągane przez połączenie ze źródłem danych, subskrybowanie danych, które chcesz dodać do strony, a następnie aktualizowanie strony w miarę nadejścia danych. Ale dlaczego nie można tego osiągnąć, po prostu zaznaczając stronę, aby określić, jakie dane powinny być pokazywane i gdzie? Cóż, może to możliwe!

Znacznik jQuery to pisać mniej, robić więcej . W sloganie opisującym wtyczkę jQuery Realtime, którą będziemy budować w tym samouczku, mniej napiszesz, robisz w czasie rzeczywistym.

W tym samouczku utworzymy wtyczkę jQuery, która bardzo ułatwi dodawanie treści w czasie rzeczywistym do strony poprzez dodanie kilku znaczników. Najpierw omówimy, jak korzystać z usługi o nazwie Popychacz subskrybować dane w czasie rzeczywistym. Następnie zdefiniujemy sposób oznaczania dokumentu HTML5 atrybutami "data- *" w sposób, który następnie może być sprawdzany przez naszą wtyczkę jQuery w czasie rzeczywistym i konwertowany na subskrypcje danych w czasie rzeczywistym. Na koniec utworzymy wtyczkę jQuery, która będzie używać atrybutów do subskrybowania danych i natychmiastowego wyświetlania aktualizacji na stronie.

Jeśli chcesz po prostu nurkować prosto, możesz zobacz wersję demonstracyjną w akcji lub możesz pobierz kod i zacznij hackować.

Podstawy Pusher

Pusher jest hostowaną usługą, która ułatwia dodawanie treści i interaktywnych treści w czasie rzeczywistym do aplikacji internetowych i mobilnych. Tutaj po prostu połączymy się, wykupimy subskrypcję niektórych danych, a następnie zaktualizujemy stronę, gdy dane się pojawią.

Aby to zademonstrować, utwórz plik o nazwie "example.html" i dołącz bibliotekę JavaScript Pusher z Pusher CDN. Wiemy, że będziemy używać jQuery 2.0.0, więc teraz powinniśmy to uwzględnić:

Creating a realtime jQuery plugin | Webdesigner Depot

Połączyć

Po dołączeniu biblioteki JavaScript Pusher możemy połączyć się z Pusherem, tworząc nową instancję "Pusher" i przekazując klucz aplikacji. Utwórz dodatkowe "

Note: For the tutorial we’ll use an application key that I’ve provided but for your own applications you’ll need to sign up to Pusher to get your own.

You can check that you’re connected in three different ways. You can do it manually by checking the Pusher Debug Console, if you load the page with the Pusher Debug Console open you’ll see the connection logged. The Pusher JavaScript library provides a log property that you can assign a function to and then you can manually check to make sure a connection has been established by inspecting the browser’s JavaScript console. Or you can check the connection programmatically by monitoring the connection state of the Pusher instance.

pusher_001

The Pusher Debug console

Whatever you choose to do, you’ll now be connected.

Subscribe

Pusher uses the Publish & Subscribe pattern, so to receive data from Pusher you first need to subscribe to it. Pusher uses the term channels when it comes to subscriptions, so let’s subscribe to a channel called ‘test-channel’.

As with connection state, you can check the status of a subscription in a few ways; using the Pusher Debug Console, by checking the output from ‘Pusher.log’ or by binding to the ‘pusher:subscription_succeeded’ event.

pusher_002

Using Pusher.log to log pusher-js library information

Bind to events

Those of you who use jQuery will probably be familiar with the idea of binding to events. jQuery does provide shortcuts for some events (e.g. ‘.onclick( )’) but you can also bind to events using ‘.bind(, )’. Pusher follows this convention and you can bind to events to be informed when something updates; when the connection state changes, when a subscription succeeds or when new application data is received. For this example, and with the realtime plugin, we’re interested primarily in the latter.

Let’s bind to a ‘test-event’ on the channel:

When binding to an event you simply identify the event by name and pass in a reference to a function that will be called when that event occurs (is triggered) on the channel.

If you have a Pusher account you can test that the ‘handleEvent’ function is called by using the Pusher Event Creator; enter ‘test-channel’ as the channel name, ‘test-event’ as the event name and some data (‘{ “some” : “data” }’) into the event data text area and click the submit button. You’ll then see the debug information, along with the data you entered, logged to the JavaScript console.

pusher_003 

Triggering an event from the Pusher Event Creator and logging it in the JavaScript console

Since the realtime jQuery plugin that we’re building doesn’t publish (trigger) data (it just consumes it) we won’t cover that here. But if you’re interested in finding out more checkout the Pusher server docs.

Displaying realtime updates

The next thing to consider is displaying the realtime data updates to the user.

For this we’ll need an idea for a simple application; having worked in finance for a few years I’m generally keen to avoid any type of financial example, but Bitcoin has made it interesting and relevant. So, let’s create a very simple display for showing Bitcoin prices.

Note: We’re going to use some fake data. Let’s make sure this doesn’t result in more Bitcoin panic selling!

First, let’s create some HTML where we’ll display the realtime prices. We can pre-populate the display with prices known at the time the page was loaded:

Bitcoin Fake Prices

LastLowHighVolume
BTC/USD61.157 USD51 USD95.713 USD66271 BTC / 4734629 USD

Let’s update the JavaScript to subscribe to a more appropriately named channel called ‘btc-usd’ and bind to a ‘new-price’ event:

The ‘data’ sent to the ‘handleEvent’ function should also be in a more appropriate format – here’s the JSON:

{"last": "last value","low": "low value","high": "high value","volume": "volume value"}

Now that we know this we can change the ‘handleEvent’ function to update the appropriate cell in the table:

function handleEvent( data ) {var cells = $( '#bitcoin_prices tbody tr td' );cells.eq( 1 ).text( data.last );cells.eq( 2 ).text( data.low );cells.eq( 3 ).text( data.high );cells.eq( 4 ).text( data.volume );}

If you now trigger a ‘new-price’ event on the ‘btc-usd’ channel, using the JSON we defined, the page will update to show the new values.

There are ways of both making this code nicer and, as the page grows to show more data, optimise things. But, we’re going to make it so that realtime data will be added to the page simply by applying markup.

Before we progress, let’s first add a bit of styling to the example. In the ‘’ add the following CSS:

As you can undoubtedly tell, I’m no designer. So please feel free to improve on this.

pusher_004

The “styled” Bitcoin Fake Prices application

Finally, restructure things so we’re set up for building the plugin.

  1. Create an ‘examples’ directory and within it a ‘bitcoin’ directory.
  2. Move the ‘example.html’ file to ‘examples/bitcoin’, rename it ‘index.html’.
  3. Create a ‘src’ directory at the top-level of the project.

The directory structure should now look as follows:

/
examples/
bitcoin/
index.html
src/

We’re now ready to define our realtime markup and build the realtime jQuery plugin.

Realtime markup

The first thing to highlight is that this isn’t a new idea — I worked for a company called Caplin Systems and in 2001 they had a technology known as RTML that let you markup a page so that realtime updates could be applied. The purpose here is to use jQuery to parse the page and then interpret the markup, resulting in subscriptions, event binding and ultimately live content being added to the page.

For our plugin we’ll use HTML5’s data-* attributes. These attributes don’t directly affect the layout or presentation of the page so they’re a great choice for our realtime markup.

The questions we now need to answer about the markup are:

  • Where do we put the Pusher application key?
  • How do we identify what channels should be subscribed to?
  • How do we identify the events that should be bound to on a channel?
  • How do we know what data to display in the page, and where?

The first one is relatively easy. Since we need to include our plugin JavaScript file we can add a ‘data-rt-key’ attribute to the ‘

So, from the script tag you can see we’re going to connect to Pusher using the key identified by ‘data-rt-key’. We’re going to subscribe to the ‘btc-usd’ channel and bind to the ‘new-price’ event. When an event is received we’re going to update the appropriate table cell based on the value indicated by ‘data-rt-value’; if the value of the attribute is ‘last’ then the value of the ‘last’ property is taken from the received ‘data’ object and displayed in the cell.

Hopefully what we are trying to achieve is now pretty clear. Let’s start looking at how to create a jQuery plugin.

jQuery plugin basics

The jQuery plugin creation docs are pretty good so I won’t go into the details here. We’ll simply concentrate on building the functionality that we need in our plugin.

Before we write any code we should consider how we want to use the plugin. The normal way a plugin functions is that you use jQuery to query the page, and then you execute the plugin functionality against the matched elements.

$( 'a' ).toggle();

The above code would find all ‘’ elements and then execute the ‘toggle()’ functionality on them — probably hiding all anchors, so not the most useful example you’ll ever see.

So, let’s say we would want to use the plugin as follows:

Spójrzmy na tworzenie oczekiwanej funkcjonalności.

Wtyczka w czasie rzeczywistym

Najpierw utwórz plik "realtime.jquery.js" w katalogu "src". Ten plik będzie zawierał funkcję wtyczki. Następnie dodaj następujący plik do pliku jako punkt początkowy naszej wtyczki:

( function( $) {$.fn.realtime = function() {console.log( 'realtime!' );console.log( $( this ).html() );}  ;} (jQuery)); 

Możemy to teraz przetestować. W 'examples / bitcoin / index.html' usuń przykładową wtyczkę '

Jeśli odświeżysz stronę, zobaczysz teraz "czas rzeczywisty"! zalogowany do konsoli JavaScript wraz z kodem HTML z '

' element. Jest to świetne, ponieważ oznacza, że ​​wtyczka działa; z powodzeniem używamy naszej funkcjonalności wtyczki na tabeli określonej przez selektor, który przekazaliśmy jQuery.

pusher_005

Wtyczki jQuery i biblioteki 3rd party

Nasza wtyczka działająca w czasie rzeczywistym opiera się na bibliotece innej firmy - bibliotece Pusher JavaScript. Na razie mamy to statycznie zawarte w naszym kodzie HTML, ale nie chcemy, aby wymagało to użycia wtyczki. Więc dynamicznie ładujmy to. jQuery zapewnia sposób łatwego robienia tego w postaci ".getScript ()" funkcjonować.

A więc załaduj wersję 2.0 biblioteki Pusher JavaScript. Załadujemy wersję hostowaną przez HTTPS, aby przeglądarki były zadowolone, jeśli nasza wtyczka jest używana na stronie obsługiwanej przez HTTPS (Chrome blokuje już próby ładowania skryptów hostowanych przez HTTP na stronach HTTPS, a Firefox zrobi to Firefox 23 ). Zamoczę ładowanie biblioteki w funkcji w następujący sposób:

var libraryLoaded = false;function loadPusher() {$.getScript( "https://d3dy5gmtp8yhk7.cloudfront.net/2.0/pusher.min.js" ).done( pusherLoaded ).fail( function( jqxhr, settings, exception ) {console.log( 'oh oh! ' + exception );}  );} function pusherLoaded (script, textStatus) {libraryLoaded = true; console.log ("pusher.min.js załadowany:" + textStatus);} loadPusher (); 

Po ponownym załadowaniu strony do konsoli zostanie zalogowany komunikat "pusher.min.js loaded: success".

W trakcie opracowywania zawsze dobrze jest mieć sposób rejestrowania informacji, więc w tym momencie stwórzmy prostą funkcję "logowania", z której możemy korzystać, która właśnie loguje się do konsoli. Wykorzystamy to teraz, a także użyjemy go do rejestrowania zdarzeń Pusher. Pełne źródło wtyczki jest teraz:

( function( $ ) {function log( msg ) {console.log( msg );}var libraryLoaded = false;function loadPusher() {$.getScript( "https://d3dy5gmtp8yhk7.cloudfront.net/2.0/pusher.min.js" ).done( pusherLoaded ).fail( function( jqxhr, settings, exception ) {log( 'oh oh! ' + exception );}  );} function pusherLoaded (script, textStatus) {libraryLoaded = true; Pusher.log = log; log ("pusher.min.js załadowany:" + textStatus);} .fn.realtime = function () {log (' w czasie rzeczywistym! '); log ($ (this) .html ());}; loadPusher ();} (jQuery)); 

Zauważysz również, że przypisaliśmy funkcję "log" do właściwości "Pusher.log". Oznacza to, że możemy zobaczyć wewnętrzne rejestrowanie biblioteki Pusher, a także nasze własne.

Kiedy powinniśmy się połączyć?

Ze względu na asynchroniczny charakter ładowania biblioteki nie możemy zagwarantować, że załaduje się, gdy nasza wtyczka zostanie wywołana. Niestety sprawia to, że rzeczy są nieco bardziej skomplikowane, niż jest to idealne, ale postaramy się rozwiązać je w możliwie prosty sposób.

Musimy sprawdzić, czy biblioteka została załadowana - stąd flaga "libraryLoaded" - i działać właściwie; jeśli biblioteka została wczytana, możemy się połączyć, a jeśli nie, musimy uruchomić ją w kolejce, aż do jej wykonania. Z tego powodu bardziej sensowne jest tworzenie instancji Pusher tylko wtedy, gdy naprawdę tego potrzebujemy, czyli wtedy, gdy faktycznie chcemy subskrybować dane.

Spójrzmy, jak możemy to zrobić:

var pending = [];function pusherLoaded( script, textStatus ) {libraryLoaded = true;while( pending.length !== 0 ) {var els = pending.shift();subscribe( els );}}function subscribe( els ) {}$.fn.realtime = function() {var els = this;if( libraryLoaded ) {subscribe( els );}else {pending.push( els );}};

Po wywołaniu wtyczki sprawdzamy flagę "libraryLoaded", aby zobaczyć, czy załadowana została biblioteka JavaScript Pusher. Jeśli jest, to dobrze, że możemy iść i możemy zasubskrybować. Jeśli nadal oczekuje na to, musimy ustawić kolejkę subskrypcji. Robimy to, przesuwając kolekcję jQuery ("els") na "oczekującą" tablicę.

Teraz połącz

Teraz, gdy wiemy, że biblioteka JavaScript Pusher została załadowana, a strona chce subskrybować dane, możemy utworzyć naszą instancję "Pusher". Ponieważ chcemy tylko jednej instancji "Pusher" na stronie, będziemy podążać za Wzór Singleton i mieć 'getPusher ()':

var pusher;function getPusher() {if( pusher === undefined ) {var pluginScriptTag = $("script[src$='jquery.realtime.js']");var appKey = pluginScriptTag.attr("data-rt-key");pusher = new Pusher( appKey );}return pusher;}

Ta funkcja pobiera tag skryptu wtyczki, szukając znacznika z atrybutem "src", który kończy się na "jquery.realtime.js", a następnie otrzymuje wartość atrybutu "data-rt-key". Następnie tworzy nową instancję "Pusher", przekazując klucz. Jak wspomniano wcześniej, utworzenie nowej instancji "Pusher" powoduje nawiązanie połączenia ze źródłem naszych danych.

Subskrybować

Możemy teraz użyć funkcji "getPusher ()", gdy tylko chcemy uzyskać dostęp do instancji "Pusher". W naszym przypadku chcemy go użyć, gdy analizujemy elementy w celu określenia subskrypcji.

Zaktualizuj funkcję zastępczą "subskrybuj" i dodaj dodatkowe funkcje pokazane poniżej:

function subscribe( els ) {var channelEls = els.find( "*[data-rt-channel]" );log( 'found ' + channelEls.size() + ' channels' );channelEls.each( subscribeChannel );}function subscribeChannel( index, el ) {el = $( el );var pusher = getPusher();var channelName = el.attr( 'data-rt-channel' );var channel = pusher.subscribe( channelName );}function find( els, selector ) {var topLevelEls = els.filter( selector );var childEls = els.find( selector );return topLevelEls.add( childEls );}

Funkcja "znajdź" jest funkcją użyteczną, która pozwala uzyskać dowolne elementy z istniejącej kolekcji, które pasują do danego selektora za pomocą '.filtr()', wraz z dowolnym potomkiem użytych elementów '.odnaleźć()'. Korzystamy z tej funkcji, aby znaleźć wszystkie elementy oznaczone do reprezentowania subskrypcji kanału (atrybut "data-rt-channel") i dla każdego z nich nazywamy "subscribeChannel". Ta funkcja wyodrębnia nazwę subskrybowanego kanału i używa wartości w wywołaniu "pusher.subscribe (channelName)", aby faktycznie zasubskrybować kanał.

Wiązać

Następnie musimy znaleźć wszystkie elementy oznaczone do reprezentowania zdarzeń (atrybut "data-rt-event"), które mają być powiązane:

function subscribeChannel( index, el ) {el = $( el );var pusher = getPusher();var channelName = el.attr( 'data-rt-channel' );var channel = pusher.subscribe( channelName );var eventEls = find( el, '*[data-rt-event]' );log( 'found ' + eventEls.size() + ' events' );eventEls.each( function( i, el) {bind( el, channel );} );}function bind( el, channel ) {el = $( el );var eventName = el.attr( 'data-rt-event' );channel.bind( eventName, function( data ) {displayUpdate( el, data );} );}function displayUpdate( el, data ) {}

Dla każdego elementu zdarzenia znajdujemy naszą własną funkcję "bind", która wiąże się ze zdarzeniem na kanale za pomocą "channel.bind (eventName, eventHandler)". Funkcja obsługi zdarzeń jest niewielkim zamknięciem, które pozwala nam przekazać aktualizację danych po ich otrzymaniu, a element zdarzenia do funkcji "displayUpdate".

Jeśli teraz to uruchomimy, z rejestru wynika, że ​​połączenie jest ustanawiane, znajdujemy jeden kanał i subskrybujemy go oraz znajdujemy jedno zdarzenie, z którym chcemy się połączyć.

pusher_006

jQuery w czasie rzeczywistym, znajdowanie subskrypcji kanałów i wiązanie zdarzeń

Wyświetl aktualizację

Kiedy wywoływana jest procedura obsługi zdarzeń, musimy znaleźć nazwę każdej właściwości w obiekcie "data" (np. Ostatni, niski, wysoki i wolumin) wysłanym wraz z aktualizacją i znaleźć elementy, które są oznaczone tą nazwą.

function bind( el, channel ) {el = $( el );var eventName = el.attr( 'data-rt-event' );channel.bind( eventName, function( data ) {displayUpdate( el, data );} );}function displayUpdate( el, data ) {for( var propName in data ) {var value = data[ propName ];var updateEls = find( el, '*[data-rt-value="' + propName + '"]' );log( 'found ' + updateEls.size() + ' "' + propName + '" elements to update' );updateEls.text( value );}}

Pętlimy nad obiektem "data" i otrzymujemy nazwę każdej właściwości. Gdy znamy nazwę właściwości ("propName"), możemy znaleźć powiązane elementy i zaktualizować ich wartość tekstową o nową wartość danych. Na razie nie będziemy obsługiwać obiektów z jakąkolwiek hierarchią - chcemy tylko jednego poziomu par klucz i wartość.

Jeśli odświeżysz stronę i uruchomisz zdarzenie z Pusher Event Creator, nowe dane będą natychmiast wyświetlane na stronie.

Czy pracowałeś z usługą transmisji danych na żywo? Jakie lekcje się nauczyłeś? Daj nam znać w komentarzach.

Wyróżniony obraz / miniatura, obraz danych na żywo przez Shutterstock.