Node.js

Vēsture

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 Mongrel tīmekļa servera un nesen izlaistā Google Chrome un 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.
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, 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 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 Event Machine un Python 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šam 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!:
// Ielādē moduli httpconst http = require('http');// Izveido serveri ar pieprasījumu apstrādātājuconst 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 serveriserver.listen(2002, '127.0.0.1', () => {
  console.log('Serveris palaists uz http://127.0.0.1:2002/');});