Node.js

***Node.js*** ir atvērtā pirmkoda, starpplatformu *[[JavaScript]]* reāllaika vide, kas ļauj izpildīt *JavaScript* kodu servera pusē.

Vēsturiski *JavaScript* tika izmantots klienta pusē, *JavaScript* rakstīto kodu ievietojot tīmekļa lappuses *HTML* kodā, un to klienta pusē lietotāja pārlūkprogrammā darbināja *JavaScript* dzinis. *Node.js* ļauj *JavaScript* rakstītu kodu darbināt servera pusē, lai veidotu dinamisku tīmekļa lappušu saturu. Tādējādi *Node.js* ir kļuvusi par "*JavaScript* visur" paradigmas pamatelementu, ļaujot tīmekļa lietotnes servera un klienta daļu rakstīt vienā programmēšanas valodā.

*Node.js* ir notikumu virzīta arhitektūra ar asinhronu ievadizvadi. Šādas arhitektūras mērķis ir caurlaides spējas optimizēšana tīmekļa lietotnēs ar daudzām ievades un izvades darbībām, kā arī reāllaika tīmekļa lietotnēs (piemēram, reāllaika sakaru programmas un pārlūkprogrammas spēles).

Lai gan ar "*.js*" apzīmē *JavaScript* failu paplašinājumu, nosaukums "*Node.js*" šajā kontekstā neattiecas un kādu atsevišķu failu, bet ir tieši produkta nosaukums.

Projektu vada fonds *Node.js Foundation*, un atbalsta *[[Linux Foundation]]* kopīgo projektu programma.

## Vēsture
thumb|left|160px|Raiens Dāls 2010. gadā
Pirmoreiz ideju *JavaScript* izmantot servera pusē 1996. gadā realizēja *[[Netscape]]* produktā *LiveWire Pro Web*, bet tas neguva plašu popularitāti.

2009. gadā ASV uzņēmuma *Joyent* programmētājs Raiens Dāls (*Ryan Dahl*) aizdomājās par *[[Flickr]]* failu lejupielādes progresa joslas darbības nepilnībām. Vēlāk viņš stāstīja: "Pārlūkprogramma nezin, cik daudz ir lejupielādēts, tāpēc tā regulāri veic pieprasījumus serverim. Tas ir līdzīgi kā tad, kad klausāties citu personu runājam: jūs taču nepārtraukti nesūtat viņam signālu, lai paziņotu, ka klausāties viņu; jūs vienkārši saņemat informāciju.
Citiem vārdiem sakot, cilvēku komunikācija nav kā programmēšanas valoda. Tā notiek haotiski, bez sinhronizācijas, un tā nav paralēla — man nav jāgaida, kamēr jūs atbildēsit, pirms atkal varu sarunāties."

Tajā laikā tīmekļa serveriem bija sarežģīti apstrādāt vairākus pieprasījumus vienlaicīgi. Nebloķējošās tīkla ligzdas bija viens no risinājumiem. Dāls aizdomājās: "Kas būtu, ja viss būtu nebloķēts? Kas būtu, ja nevajadzētu gaidīt katru ievadi un izvadi?"

Tā 2009. gada sākumā Dālam radās ideja apvienot *JavaScript* ar nebloķējošu ievadizvadi un novērtēt, vai no tā būtu sanācis kaut kas noderīgs. Viņš iedvesmojās no *[[Ruby (programmēšanas valoda)|Ruby]]* *[[Mongrel (tīmekļa serveris)|Mongrel]]* tīmekļa servera un nesen izlaistā *[[Google Chrome]]* un *[[Chrome V8|V8]]*. Četru līdz sešu mēnešu laikā Dāls izveidoja pirmo risinājumu, ko demonstrēja Eiropas *JSConf* konferencē 2009. gada 8. novembrī.
Dāla projektu sāka sponsorēt uzņēmums *Joyent*, kurā viņš strādāja.

2010. gada janvārī tika izlaists *Node.js* vides pakotnes pārvaldnieks *[[nmp (pakotnes pārvaldnieks)|nmp]]*.

Sākotnēji notikumu cilpas mehānismam tika izmantota Marka Lēmana (*Marc Lehmann*) bibliotēka *libev*. Tā kā tā darbojās tikai *Unix* vidē, tad to nevarēja izmantot *Windows* sistēmās. *Joyent* ar *[[Microsoft]]* atbalstu izstrādāja jaunu bibliotēku *[[libuv]]*, kas bija *libev* abstrakcija un varēja izmantot *Microsoft* *[[IOCP]]*. *Node.js* versija 0.5.0 ar *libuv* tika izlaista 2011. gada jūlijā.

2012. gada janvārī Dāls atgāja no projekta vadības, par projekta pārvaldītāju izvirzot *Node.js* līdzizstrādātāju un *npm* autoru Īzaku Šliteru (*Isaac Schlueter*). 2014. gada janvārī Šliters paziņoja, ka projektu vadīs Timotijs Fonteins (*Timothy J. Fontaine*).

2014. gada decembrī Fedors Indutni (*Fedor Indutny*) sāka projektu *io.js*, kas bija *Node.js* atzarojums. *Joyent* iekšējā vadības konflikta dēļ *io.js* tika veidots kā projekts ar atvērtu vadību ar atsevišķu tehnisko komiteju. Atšķirībā no *Node.js*, autori plānoja uzturēt *io.js* ar *Google V8* jaunākajiem laidieniem.

2015. gada februārī tika paziņots par nodomu izveidot neitrālu organizāciju *Node.js Foundation*. Līdz 2015. gada jūnijam *Node.js* un *io.js* kopienas nobalsoja darboties kopā *Node.js Foundation* paspārnē.
2015. gada septembrī *Node.js v0.12* un *io.js v3.3* apvienojās versijā *Node v4.0*. Tā *Node.js* ienesa *V8 ES6* iespējas, kā arī ilgtermiņa atbalsta laidienu ciklu. 2016. gadā *io.js* vietne izstrādātājiem rekomendēja pāriet uz *Node.js*, jo turpmāk vairs nav plānoti *io.js* laidieni.

## Pārskats
*Node.js* ļauj veidot tīmekļa serverus un tīklošanas programmatūru, izmantojot *JavaScript* valodu. Moduļi nodrošina failsistēmas ievadizvadi, tīklošanu (*[[DNS]]*, *[[HTTP]]*, *[[TCP]]*, *[[TLS/SSL]]* vai *[[UDP]]*), bināros datus (buferus), kriptogrāfijas funkcijas, datu plūsmas un citas kodola funkcijas. *Node.js* moduļi izmanto API, kas veidoti, lai vienkāršotu servera programmu rakstīšanu.

*Node.js* var darbināt uz *[[Linux]]*, *[[macOS]]*, *[[Solaris (operētājsistēma)|Solaris]]*, *[[FreeBSD]]*, *[[OpenBSD]]*, *[[Microsoft Windows]]* (vecākām versijām nepieciešams *[[Cygwin]]*), *[[webOS]]*, *[[NonStop OS]]* serveriem. *Node.js* var rakstīt arī citās valodās, ko var kompilēt uz *JavaScript*, piemēram, *[[CoffeeScript]]*, *[[Dart (programmēšanas valoda)|Dart]]* vai *[[TypeScript]]*.

Lielākā atšķirība no citām servera puses programmēšanas vidēm, piemēram *[[PHP]]*, ir tāda, ka *PHP* vairums funkciju bloķē citu darbību izpildi līdz funkcijas pabeigšanai (komandas izpildās tikai pēc tam, kad iepriekšējā ir pabeigta), bet *Node.js* neko nebloķē (komandas izpildās laiksakritīgi vai pat paralēli) un izmanto atzvana (*callback*) tehniku, lai signalizētu par pabeigšanu vai kļūmi.

*Node.js* līdzīgas sistēmas ir *[[Ruby (programmēšanas valoda)|Ruby]]* *Event Machine* un *[[Python]]* *[[Twisted (programmatūra)|Twisted]]*, bet *Node.js* notikumu virzītais modelis ir nedaudz attīstītāks. To veido notikumu cilpa kā izpildlaika konstrukcija, nevis kā bibliotēka. Citās sistēmās, lai startētu notikumu cilpu, notiek bloķēšanas izsaukums. *Node* vienkārši ieiet notikumu cilpā pēc ievades skripta izpildes. Savukārt iziet no notikumu cilpas tad, kad nav vairs neviena atzvana skripta, ko izpildīt.

Kamēr notikumu cilpa apstrādā asinhronos uzdevumus, *Node.js* var turpināt normāli darboties un neapgrūtināt ar procesu smagu pacelšanu. Tas padara *Node* ļoti labu tukšgaitas darbībā, kad nekas nav jādara, tā vietā, lai pastāvīgi pieprasītu papildu informāciju. Tādējādi ar *Node.js* var veidot lietojumprogrammas, kas mērogojamas miljoniem lietotāju. Turklāt notikuma cilpa netērē daudz atmiņas.

### Pavedienošana
*Node.js* darbojas ar vienu pavedienu. Tam tiek izmantota bibliotēka *[[libuv]]*, kas, savukārt, izmanto pavedienu pūlu, kas ir atbildīgs par nebloķējošām asinhronām ievadizvades operācijām. Viena pavediena kopīgošana starp visiem pieprasījumiem, kas izmanto novērotāja modeli, ir paredzēta, lai veidotu ļoti vienlaicīgas lietotnes, kur jebkurai funkcijai, kas veic ievadizvadi, jāizmanto atzvans.

Šīs viena pavediena pieejas negatīvais aspekts ir tāds, ka *Node.js* neatļauj vertikālu mērogošanu, ja palielina datora procesora kodolu skaitu. To var risināt ar papildu procesu pārvaldnieka moduli, piemēram, *Cluster*, *StrongLoop Process Manager*, *pm2*, *Forever*. Izstrādātāji var arī palielināt noklusēto pavedienu skaitu *libuv* pavedienu pūlā; šos pavedienus servera operētājsistēma, visticamāk, sadalīs pa vairākiem kodoliem.

Paralēlus uzdevumus *Node.js* apstrādā ar pavedienu pūlu. Galvenais pavediens norāda funkcijām nosūtīt uzdevumus koplietojamo uzdevumu rindā, kur pavedieni pavedienu pūlā tiek izvilkti un izpildīti. Dabiski bezbloķējošas sistēmas funkcijas, piemēram, tīklošana, pārvēršas par kodola puses bezbloķējošām tīkla ligzdām, savukārt dabiski bloķējošas sistēmas funkcijas, piemēram, failu ievadizvade, tiek palaistas bloķēšanas veidā savā pavedienā. Kad pavediens pavedienu pūlā aizpilda uzdevumu, tas informē par šo galveno pavedienu, kas, savukārt, pamostas un izpilda reģistrēto atzvanīšanas kodu.

## Koda piemērs
*HTTP* servera izveidošana un palaišana. Serveris atbild ar *[[Hello, world!]]*:

```javascript
// Ielādē moduli http
const http = require('http');

// Izveido serveri ar pieprasījumu apstrādātāju
const server = http.createServer((req, res) => {
  // Atbildes kods un http galvene
  res.writeHead(200, {
    'Content-Type': 'text/plain; charset=UTF-8'
  });
  res.end('Hello world!');
});

// Palaižam tīmekļa serveri
server.listen(2002, '127.0.0.1', () => {
  console.log('Serveris palaists uz http://127.0.0.1:2002/');
});
```


## Atsauces un piezīmes

## Ārējās saites
* Node.js Node.js Foundation