node.js
Kas ir node.js
Node.js ir platforma, kas galvenokārt paredzēta tīkla aplikāciju veidošanai, kā, piemēram, webserveris. Aplikācijas tiek rakstītas, izmantojot visiem labi zināmo JavaScript programmēšanas valodu. Node.js gadījumā JavaScript kods tiek izpildīts uz servera, nevis, kā pierasts, lietotāja interneta pārlūkprogrammā. Node.js izmanto V8 JavaScript Engine, ko ir izstrādājuši Google programmētāji un to izmanto Google Chrome interneta pārlūkprogrammā. Tradicionālais webservisu komplekts (Apache + PHP) veido pavedienus katram lapas apmeklētājam un izpilda kodu secīgi, gaidot kamēr izpildīsies I/O operācijas, tādējādi tērējot servera operatīvās atmiņas un procesora resursus. Savukārt node.js izmanto notikumu bāzētu I/O. Tas nozīmē, ka, piemēram, ja mēs izveidojam webserveri, tad node.js pasaka operētājsistēmai, lai tā informē mūs, kad tiek izveidota jauna konekcija, un kods tiek izpildīts tikai tad, kad kāds mēģina pieslēgties mūsu webserverim. Izmantojot šādu pieeju mūsu kods nekad nebloķējas. Kods tiek izpildīts tikai tad, kad ir notikusi mums interesējošā darbība.
Šādi var izveidot primitīvu "Hello World" webserveri:
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(8080);
console.log('Server running at http://127.0.0.1:8080/');
Kā uzstādīt node.js
Šīs instrukcijas ir paredzētas Ubuntu, bet uz citiem Linux distributīviem tās ir ļoti līdzīgas.
Atjaunojam paku sarakstu:
sudo apt-get update
Uzstādam nepieciešamās pakas pirms node.js uzstādīšanas:
sudo apt-get install git-core libssl-dev g++ pkg-config curl
Lejupielādējam jaunāko node.js no git repozitorija:
git clone https://github.com/joyent/node.git
Ejam uz node.js direktoriju:
cd node
Pārbaudam vai mums ir viss nepieciešamais, lai sāktu kompilēt:
./configure
Sākam kompilēt:
make
Pēc veiksmīgas kompilēšanas ieinstalējam node.js:
sudo make install
Node Package Manager
Node Package Manager (npm) ir kļuvis par galveno rīku papildus node.js bibliotēku uzstādīšanai. Node Package Manager uzstādīt ir ļoti vienkārši:
sudo curl http://npmjs.org/install.sh | sudo sh
Praktisks piemērs - čats interneta pārlūkā
Tagad, kad mums ir uzstādīts node.js un npm, izmēģināsim node.js spēku, izveidojot reālā laika čata aplikāciju interneta pārlūkā. Čata aplikācijai izmantosim socket.io bibliotēku. Lai nodrošinātu reālā laika savienojumu ar serveri uz dažādiem interneta pārlūkiem, socket.io izvēlas atbilstošāko no pārlūka atbalstītajiem transporta protokoliem.
Socket.io atbalsta šādus transporta protokolus:
- WebSocket
- Adobe Flash Socket
- AJAX long polling
- AJAX multipart streaming
- Forever Iframe
- JSONP Polling
Uzstādam socket.io bibliotēku ar npm:
sudo npm install socket.io
Mūsu čata aplikācijai ir nepieciešami 3 faili:
- server.js - kods, kas izpildīsies serverī
- chat.html - kods, kas izpildīsies klienta interneta pārlūkā
- json.js - JSON bibliotēka, kas paredzēta vecākām IE versijām
Faila server.js saturs:
var http = require('http')
, url = require('url')
, fs = require('fs')
, io = require('socket.io')
, sys = require(process.binding('natives').util ? 'util' : 'sys')
, server;
server = http.createServer(function(req, res){
// your normal server code
var path = url.parse(req.url).pathname;
switch (path){
case '/':
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('<h1>Welcome. Try the <a href="/chat.html">chat</a> example.</h1>');
res.end();
break;
case '/json.js':
case '/chat.html':
fs.readFile(__dirname + path, function(err, data){
if (err) return send404(res);
res.writeHead(200, {'Content-Type': path == '/json.js' ? 'text/javascript' : 'text/html'})
res.write(data, 'utf8');
res.end();
});
break;
default: send404(res);
}
}),
send404 = function(res){
res.writeHead(404);
res.write('404');
res.end();
};
server.listen(8080);
// socket.io, I choose you
// simplest chat application evar
var io = io.listen(server)
, buffer = [];
io.on('connection', function(client){
client.send({ buffer: buffer });
client.broadcast({ announcement: client.sessionId + ' connected' });
client.on('message', function(message){
var msg = { message: [client.sessionId, message] };
buffer.push(msg);
if (buffer.length > 15) buffer.shift();
client.broadcast(msg);
});
client.on('disconnect', function(){
client.broadcast({ announcement: client.sessionId + ' disconnected' });
});
});
Faila chat.html saturs:
<!doctype html>
<html>
<head>
<title>socket.io client test</title>
<script src="/json.js"></script> <!-- for ie -->
<script src="/socket.io/socket.io.js"></script>
</head>
<body>
<script>
function message(obj){
var el = document.createElement('p');
if ('announcement' in obj) el.innerHTML = '<em>' + esc(obj.announcement) + '</em>';
else if ('message' in obj) el.innerHTML = '<b>' + esc(obj.message[0]) + ':</b> ' + esc(obj.message[1]);
if( obj.message && window.console && console.log ) console.log(obj.message[0], obj.message[1]);
document.getElementById('chat').appendChild(el);
document.getElementById('chat').scrollTop = 1000000;
}
function send(){
var val = document.getElementById('text').value;
socket.send(val);
message({ message: ['you', val] });
document.getElementById('text').value = '';
}
function esc(msg){
return msg.replace(/</g, '<').replace(/>/g, '>');
};
var socket = new io.Socket(null, {port: 8080, rememberTransport: false});
socket.connect();
socket.on('message', function(obj){
if ('buffer' in obj){
document.getElementById('form').style.display='block';
document.getElementById('chat').innerHTML = '';
for (var i in obj.buffer) message(obj.buffer[i]);
} else message(obj);
});
socket.on('connect', function(){ message({ message: ['System', 'Connected']})});
socket.on('disconnect', function(){ message({ message: ['System', 'Disconnected']})});
socket.on('reconnect', function(){ message({ message: ['System', 'Reconnected to server']})});
socket.on('reconnecting', function( nextRetry ){ message({ message: ['System', 'Attempting to re-connect to the server, next attempt in ' + nextRetry + 'ms']})});
socket.on('reconnect_failed', function(){ message({ message: ['System', 'Reconnected to server FAILED.']})});
</script>
<h1>Sample chat client</h1>
<div id="chat"><p>Connecting...</p></div>
<form id="form" onSubmit="send(); return false">
<input type="text" autocomplete="off" id="text"><input type="submit" value="Send">
</form>
<style>
#chat { height: 300px; overflow: auto; width: 800px; border: 1px solid #eee; font: 13px Helvetica, Arial; }
#chat p { padding: 8px; margin: 0; }
#chat p:nth-child(odd) { background: #F6F6F6; }
#form { width: 782px; background: #333; padding: 5px 10px; display: none; }
#form input[type=text] { width: 700px; padding: 5px; background: #fff; border: 1px solid #fff; }
#form input[type=submit] { cursor: pointer; background: #999; border: none; padding: 6px 8px; -moz-border-radius: 8px; -webkit-border-radius: 8px; margin-left: 5px; text-shadow: 0 1px 0 #fff; }
#form input[type=submit]:hover { background: #A2A2A2; }
#form input[type=submit]:active { position: relative; top: 2px; }
</style>
</body>
</html>
Faila json.js saturs:
if(!this.JSON){JSON=function(){function f(n){return n<10?'0'+n:n;}
Date.prototype.toJSON=function(){return this.getUTCFullYear()+'-'+
f(this.getUTCMonth()+1)+'-'+
f(this.getUTCDate())+'T'+
f(this.getUTCHours())+':'+
f(this.getUTCMinutes())+':'+
f(this.getUTCSeconds())+'Z';};var m={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};function stringify(value,whitelist){var a,i,k,l,r=/["\\\x00-\x1f\x7f-\x9f]/g,v;switch(typeof value){case'string':return r.test(value)?'"'+value.replace(r,function(a){var c=m[a];if(c){return c;}
c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+
(c%16).toString(16);})+'"':'"'+value+'"';case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}
if(typeof value.toJSON==='function'){return stringify(value.toJSON());}
a=[];if(typeof value.length==='number'&&!(value.propertyIsEnumerable('length'))){l=value.length;for(i=0;i<l;i+=1){a.push(stringify(value[i],whitelist)||'null');}
return'['+a.join(',')+']';}
if(whitelist){l=whitelist.length;for(i=0;i<l;i+=1){k=whitelist[i];if(typeof k==='string'){v=stringify(value[k],whitelist);if(v){a.push(stringify(k)+':'+v);}}}}else{for(k in value){if(typeof k==='string'){v=stringify(value[k],whitelist);if(v){a.push(stringify(k)+':'+v);}}}}
return'{'+a.join(',')+'}';}}
return{stringify:stringify,parse:function(text,filter){var j;function walk(k,v){var i,n;if(v&&typeof v==='object'){for(i in v){if(Object.prototype.hasOwnProperty.apply(v,[i])){n=walk(i,v[i]);if(n!==undefined){v[i]=n;}}}}
return filter(k,v);}
if(/^[\],:{}\s]*$/.test(text.replace(/\\./g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof filter==='function'?walk('',j):j;}
throw new SyntaxError('parseJSON');}};}();}
Kad šie 3 faili ir izveidoti uz servera, atliek tikai palaist node.js ar mūsu čata aplikāciju. Lai palaistu node.js:
sudo node server.js
Mūsu čata aplikācija ir veiksmīgi palaista uz porta 8080. Atveram interneta pārlūku un notestējam node.js spēku.