چگونه یک اپلیکیشن بلادرنگ ورزشی را با نودجی‌اس بنویسیم؟

گردآوری و تالیف : ارسطو عباسی
تاریخ انتشار : 06 تیر 1397
دسته بندی ها : نود جی اس

در این آموزش قصد دارم شیوه ساخت اپلیکیشن ورزشی که می‌تواند نتایج بازی‌ها را به صورت بلاردنگ از NHL دریافت می‌کند و به کاربر نمایش دهد را توضیح دهم. امتیازها با پیشرفت بازی به صورت خودکار بروزرسانی می‌شوند. 

nodejs

این مطلب برای من بسیار هیجان برانگیز است، به این دلیل که راهی را پیدا کرده‌ام که از طریق آن بتوانم دو موضوع مورد علاقه‌ام را در کنار همدیگر قرار دهم: ورزش و برنامه‌نویسی.

تکنولوژی‌هایی که در روند این مقاله از آن‌ها استفاده می‌کنیم موارد زیر هستند:

  • Node.js
  • Socket.io
  • Mysportsfeed.com

اگر نودجی‌اس را به صورت نصب شده روی سیستم‌تان ندارید، پس نیاز است که از این صفحه آن را دانلود و نصب کنید. 

Socket.io چیست؟

Socket.io تکنولوژی است که با استفاده از آن کلاینت به سرور وصل می‌شود. در این مثال، کلاینت همان مرورگر و سرور اپلیکیشن نودجی‌اس‌ی است که قصد ایجاد آن را داریم. سرور این قابلیت را دارد که در هر زمان چندین کلاینت را به خود متصل کند. 

بعد از اینکه ارتباط برقرار شد، سرور می‌تواند به تمام کلاینت‌ها و یا تنها یک مورد منحصر به فرد پیغام ارسال کند. از این طرف نیز کلاینت می‌تواند به سرور پیام ارسال کند. در این حالت یک ارتباط بلادرنگ دو طرفه ایجاد می‌شود. 

قبل از بوجود آمدن Socket.io اپلیکیشن‌های وب از آجاکس استفاده می‌کردند، در این حالت هر دو طرف همدیگر را مجبور می‌کردند که به رویدادها توجه کنند. برای مثال هر ۱۰ ثانیه یک بار یک فراخوانی آجاکس اتفاق می‌افتاد که اگر پیامی وجود داشته باشد آن را مدیریت می‌کند.

نظارت کردن بر پیام‌ها در این حالت که معمولا بیشتر اوقات با «هیچ» مواجه می‌شد، باعث می‌شود که مصرف بسیار زیادی از طرف کلاینت و سرور بوجود بیاید.

با استفاده از Socket.io پیام‌ها بلافاصله ارسال می‌شود و این در حالتی است که نیازی به گشتن به دنبال پیام‌ها نیست و در نهایت مصرف به شدت کاهش پیدا می‌کند. 

یک اپلیکیشن ساده با Socket.io

قبل از اینکه سراغ اپلیکیشن ورزشی بروید، قصد دارم با ایجاد یک اپلیکیشن ساده، شیوه کاری Socket.io را برای شما تشریح کنم.

برای شروع من ابتدا یک اپلیکیشن نودجی‌اس را ایجاد می‌کنم. در یک پنجره کنسول یا ترمینال من به مسیر مشخصی مانند C:\GitHub\NodeJS رفته و یک پوشه جدید برای اپلیکیشن جدید ایجاد می‌کنم:

cd \GitHub\NodeJS
mkdir SocketExample
cd SocketExample
npm init

در این حالت من از تمام تنظیمات پیشفرض استفاده می‌کنم.

به دلیل آنکه ما قصد ایجاد وب اپلیکیشن را داریم، قصد دارم که از یک پکیج در NPM به نام Express استفاده کنم، چرا که با استفاده از این پکیج روند نصب و پیاده‌سازی بسیار ساده‌تر می‌شود. در یک پنجره ترمینال یا کنسول به صورت زیر می‌توانیم پکیج را نصب کنیم:

npm install express --save

در کنار این ما به یک پکیج Socket.io نیز نیاز داریم که آن را نصب کنیم:

npm install socket.io --save

بیایید با ایجاد یک وب سرور شروع کنیم. یک فایل جدید با نام index.js ایجاد کرده و کدهای زیر را برای ایجاد وب سرور با استفاده از Express در آن قرار دهید:

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');
});

اگر با Express آشنایی ندارید باید بگویم که در کدهای بالا ما کتابخانه express را در پروژه گذاشته و یک HTTP server جدید ساختیم. در این مثال سرور HTTP به پورت ۳۰۰۰ گوش می‌دهد. برای مثال: http://localhost:3000. یک مسیر نیز در کنار این کدها قرار گرفته که به مسیر ریشه وبسایت در / برگردانده می‌شود. نتیجه این مسیرها به فایل HTML به نام index.html برمی گردد.

قبل از اینکه فایل index.html ایجاد شود، بیایید سرور را پیاده‌سازی Socket.io‌ کامل کنیم. کدهای زیر را در فایل index.js قرار داده تا سرور Socket ایجاد شود:

var io = require('socket.io')(http);
 
io.on('connection', function(socket){
    console.log('Client connection received');
});

مشابه با Express کدها با وارد کردن کتابخانه Socket.io شروع شده است. این مورد در یک متغیر به نام io ذخیره می‌شود. بعد از این ما از متغیر io در کنار یک تابع رویدادی به نام on استفاده می‌کنیم. این رویداد به ارتباط کلاینت و سرور گوش می‌دهد. هر موقع که کلاینت به سرور متصل شود، این رویداد فراخوانی می‌شود.

حال بیایید یک کلاینت ساده را ایجاد کنیم. یک فایل html جدید با نام index.html ایجاد کرده و کدهای زیر را در آن قرار دهید:

<!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>

کدهای HTML جاوااسکریپت مربوط به کلاینت در Socket.io را فرخوانی کرده و یک ارتباط را با سرور ایجاد می‌کنند. برای مشاهده کردن مثال اپلیکیشن نود خودتان را به این صورت شروع کنید:

node index.js

بعد از این در مرورگر آدرس http://localhost:3000 را وارد کنید. هیچ چیزی در صفحه اصلی قرار ندارد اما اگر پنجره کنسول مربوط به مرورگر را باز کنید دو پیغام را مشاهده می‌کنید:

  • HTTP server started on port 3000
  • Client connection received

حال ما یک ارتباط سوکت موفق را داریم، بیایید از آن استفاده کنیم. برای شروع قصد داریم یک پیغام را از طرف سرور به کلاینت ارسال کنیم. بعد از اینکه کلاینت پیام را دریافت کرد، می‌تواند به سرور جواب بدهد.

به فایل index.js برگشته و کدهای زیر را در آن قرار دهید:

io.on('connection', function(socket){
    console.log('Client connection received');
     
    socket.emit('sendToClient', { hello: 'world' });
     
    socket.on('receivedFromClient', function (data) {
        console.log(data);
    });
});

تابع قبلی io.on با قرار گرفتن چند خط کد جدید بروزرسانی شد. اولین socket.emit یک پیغام را برای کلاینت ارسال می‌کند. sendToClient نیز نام رویداد است. با نامیدن رویدادها می‌توانید انواع مختلف پیام‌ها را ارسال کنید. بنابراین پیام‌ها از طرف مشتری به صورت‌های مختلفی تفسیر می‌شود. نسخه بعدی socket.on است که شامل نام رویدادها می‌شود: receivedFromClient. این مورد یک تابع را ایجاد کرده و داده‌ها را از طرف مشتری قبول می‌کند. در این حالت داده‌ها در پنجره کنسول قرار می‌گیرد.

تا به اینجای کار تمام اصلاحات مربوط به سرور به درستی قرار گرفته‌اند و تمام مشتری‌ها می‌توانند داده‌ها را دریافت و ارسال کنند.

 حال برای اینکه این مثال را تکمیل کنیم، قصد داریم رویداد sendToClient را تکمیل نماییم. این مورد می‌تواند با استفاده از رویداد receivedFromClient که به سرور برگشت داده می‌شود انجام شود.

این قسمت در بخش جاوااسکریپت مربوط به HTML باید اجرا شود، بنابراین در فایل index.html به صورت زیر قسمت جاوااسکریپت را دنبال کنید:

var socket = io();
 
socket.on('sendToClient', function (data) {
    console.log(data);
     
    socket.emit('receivedFromClient', { my: 'data' });
});

با استفاده از متغیر socket ما منطق مشابهی را در سرور با استفاده از تابع socket.on خواهیم داشت. برای قسمت کلاینت این مورد به رویداد sendToClient گوش می‌دهد. درست زمانی که کلاینت وصل شود، سرور نیز پیام خود را ارسال می‌کند. وقتی که کلاینت پیام را دریافت کرد، پیام در قسمت کنسول مرورگر قرار می‌گیرد. کلاینت نیز از همان رویداد socket.emit که سرور استفاده می‌کند، بهره می‌گیرد. در این مثال کلاینت رویداد receivedFromClient را برگشت می‌دهد. وقتی که سرور پیام را دریافت کرد، پیام در قسمت کنسول قرار می‌گیرد. 

بهتر است برای درک بیشتر خودتان آن را امتحان کنید. قسمت کنسول را باز کنید، فایل جاوااسکریپتی را اجرا نمایید: node index.js. حال وارد آدرس http://localhost:3000 شوید.

حال وارد کنسول شوید. باید با پیامی به صورت JSON در این حالت مواجه شوید: {hello: "world"}

بعد از این در قسمت خط فرمان، در حالتی که اپلیکیشن نودجی‌اس اجرا شده باید پیام‌های زیر را مشاهده کنید:

HTTP server started on port 3000
Client connection received
{ my: 'data' }

هر دو سمت سرور و کلاینت از داده‌های JSON برای اجرای یک وظیفه منحصر به فرد استفاده می‌کنند. در رابطه با این موضوع زمانی که آن‌ را به داده‌های ورزشی متصل کردیم بیشتر متوجه خواهید شد.

داده‌های ورزشی

حال که ما شیوه ارسال و دریافت داده‌ها از کلاینت و سرور را دریافتیم، می‌توانیم از این دانش برای ساخت اپلیکیشن اصلی و حالت بلادرنگ استفاده کنیم. من در این آموزش داده‌های مربوط به ورزش را انتخاب کردم، با این حال این مسئله تنها به ورزش ختم نمی‌شود و از تئوری آن می‌توان برای داده‌های دیگر نیز استفاده کرد. قبل از اینکه من این پروژه را شروع کنم من داده‌های مختلف ورزشی را جستجو کردم. یکی از موارد که من انتخاب کردم MySportsFeeds نام دارد. آن‌ها گزینه رایگانی را برای توسعه‌دهندگان در نظر گرفته اند. برای دسترسی پیدا کردن به داده‌ها به صورت بلادرنگ نیاز است که ابتدا ثبت نام کنید. همچنین برای اینکه هر ۱۰ دقیقه یکبار داده‌ها بروزرسانی شود مقدار ۱ دلار Donate کردم. البته اجباری در کار نیست.

بعد از اینکه حساب کاربری را ایجاد کردید می‌توانید تا زمان دریافت APIها ادامه دهید. برای بهتر ادامه دادن این پروسه من تصمیم گرفتم که پکیج آن‌ها را از طریق NPM دریافت کنم:

npm install mysportsfeeds-node --save

بعد از اینکه پکیج نصب شد، APIها را به صور زیر فراخوانی کردم:

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
});

در مثال بالا، مطمئن شوید که تابع authenticate را با نام کاربری و پسورد خود پر کنید. کدهای نوشته شده در بالا یک API را برای دریافت جدول رتبه‌بندی NHL دریافت می‌کند. متغیر fordate وظیفه تعیین امروز به عنوان جدول زمان‌بندی را دارد. همچنین مقدار force در این مثال برابر با True قرار گرفته است، بنابراین اگر حتی داده‌ها تغییری نکرده باشند مقدار را برمی‌گرداند. 

با پیاده‌سازی کنونی که داریم نتیجه APIها در یک فایل متنی ذخیره می‌شود. در نمونه نهایی این موضوع باید تغییر کند. با این حال تا به اینجای کار برای اینکه بتوانیم هدف اصلی را پیش ببریم، می‌توانیم سند متنی را در یک ویرایشگر متن باز کرده و خروجی آن‌ها را درک کنیم و به آن‌ها پی ببریم. نتیجه حاوی یک شیء رتبه‌بندی است. این شیء شامل یک آرایه به نام gameScore است. در این شیء نتایج مربوط به هر بازی ذخیره می‌شود. هر شیء حاوی یک شیء فرزند به نام game است. همچنین این شیء اطلاعاتی راجع به اینکه چه کسی مشغول انجام بازی است را نیز برمی گرداند.

در بیرون از شیء بازی، متغیرهای دستی وجود دارد که وضعیت کنونی بازی را نشان می‌دهد. داده‌ها براساس وضعیت بازی تغییر می‌کنند. برای مثال وقتی بازی هنوز شروع نشده است، تنها تعدادی از متغیرها وجود دارند که به ما می‌گویند بازی هنوز شروع نشده است.

زمانی که بازی در مرحله پیشرفت و اجرا قرار دارد، داده‌ها اضافی در رابطه با امتیازات و بازی قرار می‌گیرند. در کدام نیمه بازی هستند، چه مقدار زمان از بازی مانده و... . ما این موضوع را می‌توانیم زمانی که به HTML متصل شدیم مشاهده کنیم.

بروزرسانی‌های بلادرنگ

ما تمام قطعات پازل را در اختیار داریم، حال نیاز است که قطعات پازل را برای ایجاد یک تصویر در کنار همدیگر قرار دهیم. در حال حاضر MySportsFeeds قابلیت push کردن داده‌ها را برای ما ندارد پس نیاز است که ما داده‌ها از آن ها فراخوانی کنیم. خوشبختانه ما می‌دانیم که داده‌ها هر ۱۰ دقیقه یکبار تغییر پیدا می‌کنند پس نیازی نیست که به صورت مداوم به آن‌ها سر بزنیم و باعث بالا رفتن میزان مصرف داده‌ای شویم. بعد از اینکه ما داده‌ها را از آن‌ها دریافت کردیم، می‌توانیم آن‌ها را به سرور که تمام کلاینت‌ها به آن وصل هستند ارسال نماییم.

برای اجرا کردن این روند ما از تابع setInterval برای فراخوانی API در هر ۱۰ دقیقه استفاده می‌کنیم. بعد از اینکه داده‌ها دریافت شد یک رویداد برای تمام کلاینت‌ها ارسال می‌شود. بعد از اینکه کلاینت‌ها رویداد را دریافت کردند، نتایج بازی نیز با استفاده از جاوااسکریپت در مرورگر تغییر پیدا می‌کند.

MySportsFeeds همچنین در اولین شروع اپلیکیشن نودجی‌اس فراخوانی می‌شود. این داده‌ها برای هر کلاینتی که که قبل از شروع ۱۰ دقیقه متصل شده اند استفاده می‌شود. این قسمت در یک متغیر همگانی ذخیره می‌شود. این متغیر همزمان با دوره‌های تغییرات زمانی نیز تغییر پیدا می‌کند. این موضوع اطمینان این را می‌دهد که داده‌های کاربر با آخرین موارد بروزرسانی می‌شود.

برای اینکه کدهای تمیزتری داشته باشیم من یک فایل data.js نیز ایجاد کرده‌ام. فایل حاوی یک تابع است که خروجی فراخوانی قبلی API را در خود نگه می‌دارد. در اینجا می‌توانید بهتر قضیه را مشاهده کنید:

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
        });
 
};

یک تابع getData نتیجه فراخوانی را برگشت داده و خروجی می‌دهد. در این حالت یک Promise وجود دارد که اپلیکیشن اصلی را حل می‌کند.

حال بیایید نگاهی به محتوای نهایی فایل index.js بیاندازیم:

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var data = require('./data.js');
 
// Global variable to store the latest NHL results
var latestData;
 
// Load the NHL data for when client's first connect
// This will be updated every 10 minutes
data.getData().then((result) => { 
    latestData = result;
});
 
app.get('/', function(req, res){
    res.sendFile(__dirname + '/index.html');
});
 
http.listen(3000, function(){
    console.log('HTTP server started on port 3000');
});
 
io.on('connection', function(socket){
    // when clients connect, send the latest data
    socket.emit('data', latestData);
});
 
// refresh data
setInterval(function() {
    data.getData().then((result) => { 
        // Update latest results for when new client's connect
        latestData = result; 
     
        // send it to all connected clients
        io.emit('data', result);
         
        console.log('Last updated: ' + new Date());
    });
}, 300000);

ممکن است این موضوع را متوجه شده باشید که وقتی کلاینت متصل می‌شود و رویداد اتفاق می‌افتد، این اتفاق افتادن توسط یک متغیر مربوط به socket انجام می‌شود. این رویکرد باعث می‌شود که رویداد تنها برای کلاینت‌های متصل شده ارسال شود. در داخل دوره زمانی متغیر همگانی io برای اجرا کردن رویداد استفاده می‌شود. این مورد رویداد را برای تمام کلاینت‌ها ارسال می‌کند. 

این موضوع سرور را کامل می‌کند. حال بیایید روی قسمت فرانت اند کار کنیم. در یک اوایل توضیحات من یک فایل index.html را ایجاد کردم که جزئیات مربوط به اتصالات در آن‌ها قرار می‌گرفت. حال قصد دارم برای اینکه مثال کاملتری داشته باشم آن فایل را کامل‌تر کنم.

به دلیل اینکه سرور یک شیء JSON را ارسال می‌کند نیاز است که از یک پلاگین جی‌کوئری به نام JsRender استفاده کنم. این مورد یک کتابخانه قالب‌دهی است. این کتابخانه به من اجازه می‌دهد که بتوانم داده‌های بدست آمده را در یک قالب مفهوم داری استفاده کنم. در این مثال می‌توانید میزان مفید بودن و قدرتمند بودن این کتابخانه را متوجه شوید. کد نهایی بیشتر از ۴۰ خط است. من قصد دارم آن‌ را کوچکتر کنم و بعد از آن همراه با فایل HTML به صورت کامل نشان دهم. قسمت اول قصد داریم که قالبی ایجاد کنیم که داده‌های مربوط به بازی در آن قرار می‌گیرد:

<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 تعریف می‌شود. در این اسکریپت آی‌دی مربوط به قالب و یک اسکریپت منحصر به فرد به نام text/x-jsrender قرار دارد. در قالب یک کانتیر div ایجاد شده که برای نمایش هر بازی در یک قالب استفاده می‌شود. در داخل div قالب‌بندی شروع می‌شود.

در div بعدی تیم میزبان و میهمان نمایش داده می‌شود. این کار از طریق پیوند زدن نام تیم و شهر آن‌ها با همدیگر انجام می‌شود. این‌ها همان داده‌هایی است که از MySportsFeed دریافت کرده‌ایم.

{{:game.awayTeam.City}} شیء است که در زمان رندر جایگزین مقدار واقعی می‌شود. سینتکس توسط کتابخانه JsRender اجرا می‌شود. 

بعد از اینکه تیم نمایش داده شد، قسمت بعدی کد یک شرط را بررسی می‌کند. زمانی که بازی unPlayed است یک رشته در خروجی نشان داده می‌شود که در آن گفته شده که بازی در {{:game.time}} شروع می‌شود.

زمانی که بازی هنوز کامل نشده امتیاز کنونی توسط Current Score: {{:awayScore}} - {{:homeScore}} نمایش داده می‌شود. 

اگر متغیر currentIntermission مقدار مورد نیاز را به صورت خروجی نشان داد بعد از آن من تابع  ordinal_suffix_of را ایجاد کرده‌ام که نیمه‌های بازی را با اعداد نشان می‌دهد. 

وقتی بازی در نیمه نیست، من مقدار currentPeriod را نشان می‌دهم. در این قسمت باز هم از یک مقدار ordinal_suffix_of برای نمایش نیمه بازی استفاده می‌شود. 

در پایین این قسمت من یک تابع دیگر با نام time_left ایجاد کرده‌ام که برای تبدیل ثانیه‌های باقی مانده بازی به مقدار قابل خواناتری مانند دقیقه و ثانیه استفاده می‌شود. برای مثال: ۱۰:۱۲.

قسمت آخر کدها مقدار امتیازات نهایی را نمایش می‌دهد. حال می‌دانیم که بازی تمام شده است. 

در اینجا می‌توانید حالتی که در زمان پایان یافتن بازی می‌توانید مشاهده کنید را ببینید. 

مرحله بعدی یک قسمت جاوااسکریپت است که برای ایجاد Socket استفاده می‌شود. توابع کمکی ordinal_suffix_of، time_left و متغیری که برای قالب‌دهی فایل از طریق جی‌کوئری استفاده می‌شود در این قسمت قرار گرفته است.

<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>

قسمت آخر کدها، قسمتی است که برای دریافت رویدادها از socket و رندر قالب استفاده می‌شود:

socket.on('data', function (data) {
    console.log(data);
     
    $('#data').html(tmpl.render(data.scoreboard.gameScore, helpers));
});

حال من یک div با آی‌دی مربوط به داده‌ها را در اختیار دارم. نتیجه رندر قالب tmpl.render، باعث می‌شود که HTML در کانتینر نوشته شود. چیزی که در رابطه با این قسمت جذاب است این است که کتابخانه JsRender می‌تواند یک آرایه از داده‌ را نیز در این قسمت دریافت کند.

فایل HTML و Javascript نهایی به صورت زیر است:

<!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>

اپلیکیشن نودجی‌اس را اجرا کنید و در مرورگر آدرس http://localhost:3000 را بنویسید. حال می‌توانید نتیجه نهایی را مشاهده کنید.

در هر x دقیقه سرور یک رویداد را برای کلاینت ارسال می‌کند. کلاینت المان‌های بازی را دوباره طراحی کرده و داده‌های جدید را بروزرسانی می‌کند. بنابراین وقتی وبسایت را ببندید و باری دیگر آن را باز کنید می‌توانید داده‌های تازه را مشاهده نمایید.

در پایان

محصول نهایی ایجاد شده از Socket.io برای ایجاد سرور که کلاینت قابلیت اتصال به وی را دارد استفاده شده است. سرور داده‌ها را دریافت کرده و آن‌ها را به کلاینت برمی‌گرداند. زمانی که کلاینت داده‌ها را دریافت کرد، داده‌ها می‌توانند به صورت یکپارچه بروزرسانی شوند و نمایش یابند. این موضوع بارگذاری روی سرور را کاهش می‌دهد به این دلیل که کلاینت تنها زمانی کار می‌کند که رویدادی دریافت شود.

Socketها تنها در یک مسیر محدود نشده‌اند. کلاینت نیز می‌تواند برای سرور اطلاعات ارسال کند. زمانی که سرور اطلاعاتی را دریافت کرد می‌تواند پردازش شود.

اپلیکیشن‌های چت امروزی درست به این صورت کار می‌کنند. سرور باید یک پیام را از کلاینت دریافت کند و بعد آن را برای کلاینت‌های دیگر ارسال نماید. اینگونه است که کسی متوجه دریافت پیام جدید می‌شود.

امیدوارم از این مقاله خوشتان آمده باشد و توانسته باشید که اپلیکیشن خودتان را ایجاد کنید.

منبع

مقالات پیشنهادی

چگونه یک وبسایت وردپرسی را به یک اپلیکیشن موبایل تبدیل کنیم

داشتن یک وبسایت واکنشگرا یکی از مهمترین مواردی است که دارندگان وبسایت باید به آن توجه کنند، با این کار آن ها می توانند تمام اطلاعات وبسایت را در دستگا...

ساخت اپلیکیشن مقیاس بزرگ با Jooby

Jooby یک میکرو فریمورک ماژولار برای ساخت اپلیکیشن ها در جاوا و Kotlin هست. اگر این اولین باره که درمورد Jooby می شونید, میتونید این لینک رو مطالعه کنی...

۱۱ اپلیکیشن موبایل برای طراحان وب

یکی از خوبی‌های فریلنسر بودن این است که شما تقریبا در هر جایی می‌توانید کارهای‌تان را انجام دهید. با این حال فشار کاری و مداوم نشستن پشت یک کامپیوتر م...

۵ پلتفرم برای ساخت اپلیکیشن بدون نیاز به کدنویسی

با افزایش استفاده از تلفن‌های هوشمند، اپلیکیشن‌های موبایل به پر استفاده ترین پلتفرم‌های حال حاضر تبدیل شده اند. توسعه‌دهندگان کنونی نیز استعداد‌های خو...