
Dans cet article, je vais montrer comment créer une application Web à l'aide de Node.js, qui vous permet de suivre les résultats des matchs de la LNH en temps réel. Les indicateurs sont mis à jour en fonction des changements de score pendant les matchs.
J'ai vraiment aimé écrire cet article, car y travailler comprenait deux choses que j'aimais: le développement de logiciels et le sport.
Au cours des travaux, nous utiliserons les outils suivants:
- Node.js;
- Socket.io;
- MySportsFeed.com.
Si vous n'avez pas installé Node.js, visitez la page de téléchargement et installez, puis nous continuerons.
Qu'est-ce que socket.io?
Il s'agit de la technologie qui connecte le client au serveur. Dans l'exemple actuel, le client est un navigateur Web et le serveur est le Node.js. Le serveur peut fonctionner simultanément avec plusieurs clients à tout moment.
Une fois la connexion établie, le serveur peut envoyer des messages à tous les clients ou à un seul d'entre eux. Cela, à son tour, peut envoyer des messages au serveur, fournissant une communication dans deux directions.
Avant Socket.io, les applications Web fonctionnaient généralement sur AJAX. Son utilisation prévoyait la nécessité pour le client d'interroger le serveur et vice versa à la recherche de nouveaux événements. Par exemple, de tels sondages pourraient être effectués toutes les 10 secondes pour rechercher de nouveaux messages.
Cela représentait une charge supplémentaire, car la recherche de nouveaux messages était effectuée même lorsqu'ils ne l'étaient pas du tout.
Lorsque vous utilisez Socket.io, les messages sont reçus en temps réel sans qu'il soit nécessaire de vérifier constamment leur présence, ce qui réduit la charge.
Exemple d'application Socket.io
Avant de commencer à collecter des données de concurrence en temps réel, créons un exemple d'application pour montrer comment Socket.io fonctionne.
Tout d'abord, je vais créer une application Node.js. Dans la fenêtre de la console, vous devez aller dans le répertoire C: \ GitHub \ NodeJS, créer un nouveau dossier pour l'application et dans celle-ci une nouvelle application:
cd \GitHub\NodeJS mkdir SocketExample cd SocketExample npm init
J'ai laissé les paramètres par défaut, vous pouvez faire de même.
Comme nous créons une application Web, j'utiliserai un package NPM appelé Express pour simplifier l'installation. À l'invite de commandes, exécutez les commandes suivantes: npm install express --save.
Bien sûr, nous devons également installer le package Socket.io: npm install socket.io --save
Vous devez maintenant démarrer le serveur Web. Pour ce faire, créez un nouveau fichier index.js et placez la section de code suivante:
var app = require('express')(); var http = require('http').Server(app); app.get('/', function(req, res){ res.sendFile(__dirname + '/index.html'); }); http.listen(3000, function(){ console.log('HTTP server started on port 3000'); });
Si Express ne vous est pas familier, alors l'exemple de code ci-dessus inclut la bibliothèque Express, nous créons ici un nouveau serveur HTTP. Dans l'exemple, le serveur HTTP écoute sur le port 3000, c'est-à-dire
localhost : 3000. Le chemin va à la racine, «/». Le résultat est renvoyé sous forme de fichier HTML index.html.
Avant de créer ce fichier, terminons le démarrage du serveur en configurant Socket.io. Pour créer un serveur Socket, exécutez les commandes suivantes:
var io = require('socket.io')(http); io.on('connection', function(socket){ console.log('Client connection received'); });
Comme pour Express, le code commence par importer la bibliothèque Socket.io. Ceci est indiqué par la variable io. Ensuite, en utilisant cette variable, créez un gestionnaire d'événements avec la fonction on. Cet événement est déclenché chaque fois qu'un client se connecte au serveur.
Créons maintenant un client simple. Pour ce faire, créez le fichier index.html et placez le code suivant à l'intérieur:
<!doctype html> <html> <head> <title>Socket.IO Example</title> </head> <body> <script src="/socket.io/socket.io.js"></script> <script> var socket = io(); </script> </body> </html>
Le code HTML ci-dessus charge le client JavaScript Socket.io et initialise la connexion au serveur. Pour voir un exemple, exécutez Node: node index.js.
Ensuite, dans le navigateur, entrez
localhost : 3000. La page restera vierge, mais si vous regardez la console pendant que Node est en cours d'exécution, vous verrez deux messages:
Le serveur HTTP a démarré sur le port 3000
Connexion client reçueMaintenant que nous sommes connectés avec succès, continuons le travail. Par exemple, envoyez un message au client à partir du serveur. Ensuite, lorsque le client le recevra, un message de réponse sera envoyé:
io.on('connection', function(socket){ console.log('Client connection received'); socket.emit('sendToClient', { hello: 'world' }); socket.on('receivedFromClient', function (data) { console.log(data); }); });
La fonction io.on précédente a été mise à jour pour inclure plusieurs nouvelles lignes de code. Le premier, socket.emit, envoie un message au client. sendToClient est le nom de l'événement. En nommant les événements, vous avez la possibilité d'envoyer différents types de messages afin que le client puisse les interpréter différemment. Une autre mise à jour est socket.on, qui a également un nom d'événement: receivedFromClient. Tout cela crée une fonction qui reçoit des données du client. Dans ce cas, ils sont également enregistrés dans la fenêtre de la console.
Les étapes terminées complètent la préparation du serveur. Il peut désormais recevoir et envoyer des données à partir de n'importe quel client connecté.
Terminons cet exemple en mettant à jour le client en recevant l'événement sendToClient. Lorsqu'un événement est reçu, une réponse est reçue de FromClient.
Ceci conclut la partie JavaScript de HTML. Dans index.html, ajoutez:
var socket = io(); socket.on('sendToClient', function (data) { console.log(data); socket.emit('receivedFromClient', { my: 'data' }); });
En utilisant la variable socket intégrée, nous obtenons une logique similaire sur le serveur avec la fonction socket.on. Le client écoute l'événement sendToClient. Dès que le client est connecté, le serveur envoie ce message. Le client, le recevant, enregistre l'événement dans la console du navigateur. Après cela, le client utilise le même socket.emit que le serveur utilisé pour envoyer l'événement d'origine. Dans ce cas, le client envoie l'événement FromClient reçu au serveur. Lorsqu'il reçoit un message, il est enregistré dans la fenêtre de la console.
Essayez-le vous-même. Tout d'abord, dans la console, lancez votre application Node: node index.js.
Chargez ensuite
localhost : 3000 dans le navigateur.
Vérifiez la console de votre navigateur et vous verrez ce qui suit dans les journaux JSON: {hello: "world"}
Ensuite, pendant que l'application Node est en cours d'exécution, vous verrez ce qui suit:
Le serveur HTTP a démarré sur le port 3000
Connexion client reçue
{my: 'data'}Le client et le serveur peuvent utiliser les données JSON pour effectuer des tâches spécifiques. Voyons comment vous pouvez travailler avec les données de la concurrence en temps réel.
Informations sur la compétition
Après avoir compris les principes d'envoi et de réception de données par le client et le serveur, il convient d'essayer de s'assurer que les mises à jour sont effectuées en temps réel. J'ai utilisé les données de compétition, bien que la même chose puisse être faite non seulement avec les informations sportives. Mais puisque nous y travaillons, nous devons trouver la source. Ils serviront
MySportsFeeds . Le service est payant - à partir de 1 $ par mois, n'oubliez pas.
Une fois votre compte configuré, vous pouvez commencer avec leur API. Vous pouvez utiliser le package NPM pour cela: npm install mysportsfeeds-node --save.
Après avoir installé le package, nous connectons l'API:
var MySportsFeeds = require("mysportsfeeds-node"); var msf = new MySportsFeeds("1.2", true); msf.authenticate("********", "*********"); var today = new Date(); msf.getData('nhl', '2017-2018-regular', 'scoreboard', 'json', { fordate: today.getFullYear() + ('0' + parseInt(today.getMonth() + 1)).slice(-2) + ('0' + today.getDate()).slice(-2), force: true });
Dans l'exemple ci-dessus, remplacez mes données par les vôtres.
Le code effectue un appel API pour obtenir les résultats des compétitions de la LNH d'aujourd'hui. La variable fordate est ce qui définit la date. J'ai également utilisé la force et la vérité pour récupérer les données même si les résultats sont les mêmes.
Avec la configuration actuelle, les résultats de l'appel d'API sont écrits dans un fichier texte. Dans le dernier exemple, nous allons changer cela; à des fins de démonstration, le fichier de résultats peut être consulté dans un éditeur de texte pour comprendre le contenu de la réponse. Dans notre résultat, nous voyons l'objet de table de résultats. Cet objet contient un tableau appelé gameScore. Il enregistre le résultat de chaque match. Chaque objet contient à son tour un objet enfant appelé jeu. Cet objet fournit des informations sur qui joue.
En dehors de l'objet de jeu, plusieurs variables affichent l'état actuel du jeu. Les données changent en fonction de leurs résultats. Lorsque le jeu n'a pas encore commencé, des variables sont utilisées qui fournissent des informations sur le moment où cela se produira. Lorsque le jeu a commencé, des données supplémentaires sont fournies sur les résultats, y compris des informations sur la période actuelle et le temps restant. Afin de mieux comprendre ce qui est en jeu, passons à la section suivante.
Mises à jour en temps réel
Nous avons toutes les pièces du puzzle, alors assemblons-le! Malheureusement, MySportsFeeds a un support limité pour l'émission de données, vous devez donc constamment demander des informations. Il y a un point positif ici: nous savons que les données ne changent qu'une fois toutes les 10 minutes, il n'est donc pas nécessaire d'interroger le service trop souvent. Les données reçues peuvent être envoyées du serveur à tous les clients connectés.
Pour obtenir les données nécessaires, j'utiliserai la fonction JavaScript setInterval, qui vous permet d'accéder à l'API (dans mon cas) toutes les 10 minutes pour trouver des mises à jour. Lorsque les données arrivent, l'événement est envoyé à tous les clients connectés. Les résultats sont ensuite mis à jour via JavaScript dans un navigateur Web.
MySportsFeeds est également appelé lorsque l'application Node est lancée en premier. Les résultats seront utilisés pour tous les clients qui se connectent avant le premier intervalle de 10 minutes. Les informations à ce sujet sont stockées dans une variable globale. À son tour, il est mis à jour dans le cadre d'une enquête par intervalles. Cela garantit que chacun des clients aura des résultats pertinents.
Pour que tout se passe bien dans le fichier principal index.js, j'ai créé un nouveau fichier appelé data.js. Il contient une fonction exportée depuis index.js qui effectue un appel précédent à l'API MySportsFeeds. Voici le contenu complet de ce fichier:
var MySportsFeeds = require("mysportsfeeds-node"); var msf = new MySportsFeeds("1.2", true, null); msf.authenticate("*******", "******"); var today = new Date(); exports.getData = function() { return msf.getData('nhl', '2017-2018-regular', 'scoreboard', 'json', { fordate: today.getFullYear() + ('0' + parseInt(today.getMonth() + 1)).slice(-2) + ('0' + today.getDate()).slice(-2), force: true }); };
La fonction getData est exportée et renvoie les résultats de l'appel. Voyons ce que nous avons dans le fichier index.js.
var app = require('express')(); var http = require('http').Server(app); var io = require('socket.io')(http); var data = require('./data.js');
Les sept premières lignes de code ci-dessus initialisent les bibliothèques requises et appellent la variable globale latestData. La dernière liste des bibliothèques utilisées est: Express, Http Server, créée à l'aide d'Express, Socket.io plus le fichier data.js qui vient d'être créé.
En tenant compte des besoins, l'application remplit les dernières données (latestData) pour les clients qui se connectent au premier démarrage du serveur:
Les quelques lignes suivantes définissent le chemin de la page principale du site (dans notre cas
localhost : 3000 /) et demandent au serveur HTTP d'écouter sur le port 3000.
Socket.io est ensuite configuré pour rechercher de nouvelles connexions. Lorsqu'elles sont détectées, le serveur envoie des données d'événement avec le contenu de la dernière variable Data.
Et enfin, le dernier morceau de code crée l'intervalle d'interrogation requis. Lorsqu'elle est détectée, la variable latestData est mise à jour avec les résultats de l'appel d'API. Ces données transmettent ensuite le même événement à tous les clients.
Comme nous le voyons, lorsqu'un client se connecte et qu'un événement est défini, il est émis avec une variable socket. Cela vous permet d'envoyer un événement à un client connecté spécifique. Dans l'intervalle, l'io global est utilisé pour distribuer l'événement. Il envoie des données à tous les clients. La configuration du serveur est terminée.
À quoi cela ressemblera
Maintenant, travaillons sur le frontend du client. Dans un premier exemple, j'ai créé le fichier de base index.html, qui établit une connexion avec le client pour enregistrer les événements du serveur et les envoyer. Je vais maintenant étendre les capacités du fichier.
Puisque le serveur nous envoie un objet JSON, j'utiliserai jQuery et une extension jQuery appelée JsRender. Il s'agit d'une bibliothèque de modèles. Cela me permettra de créer un modèle HTML qui sera utilisé pour afficher le contenu de chaque match de la LNH de manière pratique. Vous pouvez maintenant voir l'étendue de ses capacités. Le code contient plus de 40 lignes, donc je vais le diviser en plusieurs sections plus petites, et à la fin je montrerai tout le contenu HTML.
Voici ce qui est utilisé pour afficher les données du jeu:
<script id="gameTemplate" type="text/x-jsrender"> <div class="game"> <div> {{:game.awayTeam.City}} {{:game.awayTeam.Name}} at {{:game.homeTeam.City}} {{:game.homeTeam.Name}} </div> <div> {{if isUnplayed == "true" }} Game starts at {{:game.time}} {{else isCompleted == "false"}} <div>Current Score: {{:awayScore}} - {{:homeScore}}</div> <div> {{if currentIntermission}} {{:~ordinal_suffix_of(currentIntermission)}} Intermission {{else currentPeriod}} {{:~ordinal_suffix_of(currentPeriod)}}<br/> {{:~time_left(currentPeriodSecondsRemaining)}} {{else}} 1st {{/if}} </div> {{else}} Final Score: {{:awayScore}} - {{:homeScore}} {{/if}} </div> </div> </script>
Le modèle est défini à l'aide de la balise de script. Il contient un identifiant de modèle et un type de script spécial appelé text / x-jsrender. Le modèle définit un conteneur div pour chaque jeu qui contient une classe de jeu pour appliquer un style de base spécifique. À l'intérieur de cette div se trouve le début du modèle.
Le div suivant affiche l'équipe invitée et l'équipe hôte. Ceci est mis en œuvre en combinant le nom de la ville et le nom de l'équipe avec l'objet de jeu à partir des données MySportsFeeds.
{{: game.awayTeam.City}} est la façon dont je définis un objet qui sera remplacé par une valeur physique lors du rendu du modèle. Cette syntaxe est définie par la bibliothèque JsRender.
Lorsque le jeu n'est pas joué, une ligne apparaît dans laquelle le jeu commence par {{: game.time}}.
Jusqu'à la fin du jeu, le score actuel est affiché: {{: awayScore}} - {{: homeScore}}. Et, enfin, une petite astuce qui permettra de déterminer quelle est la période actuelle, et de clarifier s'il y a une pause maintenant.
Si la variable currentIntermission apparaît dans les résultats, alors j'utilise la fonction I, définie par ordinal_suffix_of, qui convertit le numéro de période dans le texte suivant: 1er (2e, 3e, etc.) Break.
Quand il n'y a pas de pause, je cherche la valeur de currentPeriod. Ordinal_suffix_of est également utilisé ici pour montrer que le jeu est dans les 1ère (2e, 3e, etc.) périodes.
De plus, une autre fonction que j'ai définie comme time_left est utilisée pour convertir le nombre de secondes restantes jusqu'à la fin de la période. Par exemple: 10:12.
La dernière partie du code affiche le résultat final lorsque le jeu est terminé.
Voici un exemple de l'apparence d'une liste mixte de jeux terminés, de jeux qui ne sont pas encore terminés et de jeux qui n'ont pas encore commencé (je ne suis pas un très bon concepteur, donc le résultat semble être le cas lorsque le développeur crée une personnalisation). interface d'application à faire soi-même):

Ensuite, un extrait de code JavaScript qui crée un socket, les fonctions d'assistance ordinal_suffix_of et time_left, et une variable qui fait référence au modèle jQuery généré.
<script> var socket = io(); var tmpl = $.templates("#gameTemplate"); var helpers = { ordinal_suffix_of: function(i) { var j = i % 10, k = i % 100; if (j == 1 && k != 11) { return i + "st"; } if (j == 2 && k != 12) { return i + "nd"; } if (j == 3 && k != 13) { return i + "rd"; } return i + "th"; }, time_left: function(time) { var minutes = Math.floor(time / 60); var seconds = time - minutes * 60; return minutes + ':' + ('0' + seconds).slice(-2); } }; </script>
Le dernier fragment est le code pour recevoir l'événement socket et rendre le modèle:
socket.on('data', function (data) { console.log(data); $('#data').html(tmpl.render(data.scoreboard.gameScore, helpers)); });
J'ai un délimiteur avec un identifiant de données. Le résultat du rendu de modèle (tmpl.render) écrit du HTML dans ce conteneur. Ce qui est vraiment cool - la bibliothèque JsRender peut prendre un tableau de données, dans ce cas data.scoreboard.gameScore, qui parcourt chaque élément du tableau et crée un jeu par élément.
Voici la version finale promise ci-dessus, où HTML et JavaScript sont combinés:
<!doctype html> <html> <head> <title>Socket.IO Example</title> </head> <body> <div id="data"> </div> <script id="gameTemplate" type="text/x-jsrender"> <div class="game"> <div> {{:game.awayTeam.City}} {{:game.awayTeam.Name}} at {{:game.homeTeam.City}} {{:game.homeTeam.Name}} </div> <div> {{if isUnplayed == "true" }} Game starts at {{:game.time}} {{else isCompleted == "false"}} <div>Current Score: {{:awayScore}} - {{:homeScore}}</div> <div> {{if currentIntermission}} {{:~ordinal_suffix_of(currentIntermission)}} Intermission {{else currentPeriod}} {{:~ordinal_suffix_of(currentPeriod)}}<br/> {{:~time_left(currentPeriodSecondsRemaining)}} {{else}} 1st {{/if}} </div> {{else}} Final Score: {{:awayScore}} - {{:homeScore}} {{/if}} </div> </div> </script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jsrender/0.9.90/jsrender.min.js"></script> <script src="/socket.io/socket.io.js"></script> <script> var socket = io(); var helpers = { ordinal_suffix_of: function(i) { var j = i % 10, k = i % 100; if (j == 1 && k != 11) { return i + "st"; } if (j == 2 && k != 12) { return i + "nd"; } if (j == 3 && k != 13) { return i + "rd"; } return i + "th"; }, time_left: function(time) { var minutes = Math.floor(time / 60); var seconds = time - minutes * 60; return minutes + ':' + ('0' + seconds).slice(-2); } }; var tmpl = $.templates("#gameTemplate"); socket.on('data', function (data) { console.log(data); $('#data').html(tmpl.render(data.scoreboard.gameScore, helpers)); }); </script> <style> .game { border: 1px solid #000; float: left; margin: 1%; padding: 1em; width: 25%; } </style> </body> </html>
Il est maintenant temps de lancer l'application Node et d'ouvrir
localhost : 3000 afin de voir le résultat!
Toutes les X minutes, le serveur envoie un événement au client. Le client, à son tour, redessinera les éléments du jeu avec des données mises à jour. Par conséquent, lorsque vous laissez le site ouvert, les résultats des jeux seront constamment mis à jour.
Conclusion
Le produit final utilise Socket.io pour créer un serveur auquel les clients se connectent. Le serveur récupère les données et les envoie au client. Lorsqu'un client reçoit des données, il peut mettre à jour les résultats progressivement. Cela réduit la charge sur le serveur car le client n'agit que lorsqu'il reçoit un événement du serveur.
Le serveur peut envoyer des messages au client et le client, à son tour, au serveur. Lorsque le serveur reçoit le message, il effectue le traitement des données.
Les applications de chat fonctionnent de la même manière. Le serveur recevra un message du client, puis transmettra toutes les données aux clients connectés pour indiquer que quelqu'un a envoyé un nouveau message.
J'espère que vous avez apprécié cet article, car lorsque j'ai développé cette application sportive en temps réel, je viens de recevoir une montagne de plaisir que je voulais partager avec mes connaissances. Après tout, le hockey est l'un de mes sports préférés!
