Se execută javascript pe serverul IIS

dinRisingStack . Tradus cu permisiunea deținătorilor drepturilor de autor.

În acest capitol, vă voi prezenta modul în care puteți porni un server HTTP simplu în Node.js și puteți începe procesarea cererilor.

modul http pentru serverul dvs. Node.js

Când începeți să construiți aplicații HTTP în Node.js, modulele încorporate http/https sunt cu care veți interacționa.

Să creăm primul tău server HTTP cu Node.js! Va trebui să conectăm modulul http și să ne legăm serverul la portul 3000.

// index de conținut.js
const http = necesită ("http")
const port = 3000 const requestHandler = (cerere, răspuns) => (
console.log(request.url)
response.end ("Salut Node.js Server!")
) const server = http.createServer(requestHandler) server.listen(port, (err) => (
dacă (greș) (

})

Apoi rulăm acest script:

$nodeindex.js

Lucruri de remarcat aici:

  • requestHandler: Această funcție va fi apelată de fiecare dată când o solicitare vine la server. Dacă deschideți localhost:3000 în browser, vor apărea două mesaje în consolă: unul pentru / și unul pentru favicon.ico .
  • if (err) : gestionarea erorilor: dacă portul este deja ocupat sau există alte motive pentru care serverul nu poate fi pornit, vom primi o notificare despre acest lucru.

Modulul http are un nivel extrem de scăzut: crearea unei aplicații web complexe folosind fragmentul de cod de mai sus necesită foarte multă muncă. Din acest motiv alegem de obicei cadre pentru a lucra la proiectele noastre. Există multe cadre, iată cele mai populare:

  • expres
  • hapi
  • koa
  • restabili

În acest capitol și în următoarele, vom folosi Express, deoarece pentru asta puteți găsi o mulțime de module în NPM.

Expres

Cadru web rapid, flexibil și minimalist pentru Node.js — http://expressjs.com/

Adăugarea Express la proiectul dvs. este o instalare simplă prin NPM:

$ npm install express --save

După ce ați instalat Express, să vedem cum să creați o aplicație similară cu ceea ce am scris mai devreme:


const app = expres()
const port = 3000 app.get(‘/’, (cerere, răspuns) => (
response.send("Bună ziua de la Express!")
)) app.listen(port, (err) => (
dacă (greș) (
return console.log(„s-a întâmplat ceva rău”, err)
) console.log(`serverul ascultă pe $(port)`)
})

Cea mai mare diferență pe care o puteți observa aici este că Express vă oferă un router implicit. Nu trebuie să analizați manual adresa URL pentru a decide ce să faceți, în schimb definiți rutarea aplicației cu app.get , app.post , app.put și așa mai departe, iar acestea sunt deja traduse în solicitările HTTP corespunzătoare.

Unul dintre cele mai puternice concepte pe care Express le implementează este modelul Middleware.

Middleware — procesor intermediar

Vă puteți gândi la middleware ca la conducte Unix, dar pentru solicitări HTTP.

În diagramă puteți vedea cum trece cererea prin aplicația condiționată Express. Trece prin trei procesoare intermediare. Fiecare handler poate modifica această solicitare și apoi, pe baza logicii dvs. de afaceri, un al treilea middleware va trimite un răspuns, sau cererea va merge către handlerul de rută corespunzător.

În practică, ai putea proceda astfel:

Const expres = necesită ("express")
const app = express() app.use((cerere, răspuns, următor) => (
console.log(request.headers)
Următorul()
)) app.use((cerere, răspuns, următorul) => (
request.chance = Math.random()
Următorul()
)) app.get("/", (cerere, răspuns) => (
response.json((
şansă: cerere.şansă
})
)) app.listen(3000)

Lucruri de remarcat aici:

  • app.use: Acesta este modul în care puteți descrie middleware. Această metodă preia o funcție cu trei parametri, primul dintre care este cererea, al doilea este răspunsul, iar al treilea este următorul apel invers. Apelarea următoarei semnalează că poate trece la următorul middleware.
  • Primul middleware înregistrează doar anteturile și îl apelează imediat pe următorul.
  • Al doilea adaugă o proprietate suplimentară cererii — aceasta este una dintre cele mai puternice caracteristici ale șablonului middleware. Middleware-ul dvs. poate adăuga date suplimentare la obiectul de solicitare, care pot fi citite/modificate de middleware de mai jos.

Eroare la procesare

Ca și în cazul tuturor cadrelor, gestionarea corectă a erorilor este critică. În Express, trebuie să creați un middleware special cu patru parametri de intrare:

Const express = cere(‘express’)
const app = express() app.get(‘/’, (cerere, răspuns) => (
aruncă o nouă eroare („hopa”)
)) app.use((erre, cerere, răspuns, următor) => (
// înregistrarea erorii, doar console.log pentru moment
console.log(err)
response.status(500).send(‘S-a stricat ceva!’)
)) app.listen(3000)

Lucruri de remarcat aici:

  • Managerul de erori ar trebui să fie ultima functie adăugat cu app.use .
  • Managerul de erori acceptă următorul apel invers. Poate fi folosit pentru a combina mai mulți manipulatori de erori.

Redare HTML

Anterior, ne-am uitat la cum să trimitem răspunsuri JSON. Este timpul să învățați cum să redați HTML într-un mod simplu. Pentru a face acest lucru, vom folosi pachetul de ghidon cu învelișul pentru ghidon expres.

Mai întâi, să creăm următoarea structură de directoare:

├── index.js
└──viziuni
├──acasă.hbs
└── machete
└── principal.hbs

După aceea, completați index.js cu următorul cod:

//index.js
cale const = necesită ("cale")
const express = cere("express")
const exphbs = require("ghidon expres")
const app = express() app.engine(".hbs", exphbs((
defaultLayout: „principal”,
extname: ".hbs",
layoutsDir: path.join(__dirname, "views/layouts")
}))
app.set(„vizualizare motor”, „.hbs”)
app.set(„views”, path.join(__dirname, „views”))
app.listen(3000)

Codul de mai sus inițializează motorul ghidonului și setează directorul șablonului la vizualizări/aspecte. Acesta este directorul în care vor fi stocate șabloanele dvs.

Odată ce ați făcut această configurare, puteți pune codul html inițial în main.hbs . Pentru a ușura lucrurile, să trecem direct la asta:



Ghidon expres


(((corp)))

Este posibil să observați o etichetă (((corpul))) — conținutul dvs. va fi postat aici. Să creăm home.hbs!

Salut ((nume))

Ultimul lucru pe care trebuie să-l facem pentru ca toate acestea să funcționeze este să adăugăm un handler de rută la aplicația noastră Express:

App.get("/", (cerere, răspuns) => (
response.render("acasă", (
nume: "Ioan"
})
})

Metoda de randare ia doi parametri:

  • Primul este numele șablonului.
  • Al doilea sunt datele necesare pentru randare.

Odată ce faci o cerere la această adresă, vei primi ceva de genul:



Ghidon expres


Bună, John



Acesta este doar vârful aisbergului. Pentru a afla cum să adăugați mai multe șabloane (și chiar parțiale), vă rugăm să consultați documentația oficială a ghidonului expres.

Depanare Express

În unele cazuri, poate fi necesar să vă dați seama ce se întâmplă cu Express în timp ce aplicația rulează. Pentru a face acest lucru, puteți trece următoarea variabilă de mediu către Express: DEBUG=express* .

Ar trebui să porniți serverul HTTP Node.js folosind:

$ DEBUG=express* nod index.js

rezumat

Iată cum vă puteți configura primul server HTTP Node.js de la zero. Recomand Express pentru a începe și apoi a experimenta.

Figura 2.1 Arhitectura unui mediu de aplicație client-server în JavaScript

Cele trei straturi sunt:

  • Clienți WWW (cum ar fi clienții Netscape Navigator): Acest strat oferă aplicației o interfață multiplatformă cu utilizatorul final. Acest strat poate conține, de asemenea, o anumită logică a aplicației, cum ar fi regulile de validare a datelor implementate în JavaScript la nivelul clientului. Clienții pot fi în interiorul sau în afara proxy-ului rețelei corporative.
  • Server Netscape WWW/client DB: Acest strat constă dintr-un server Netscape cu JavaScript activat. Conține logica aplicației, se ocupă de securitate și controlează accesul la aplicație pentru mai mulți utilizatori folosind JavaScript pe partea de server. Acest nivel permite clienților atât în ​​interiorul, cât și în afara domeniului de aplicare al proxy-ului să acceseze aplicația. Serverul WWW funcționează și ca client cu orice server instalat DB.
  • Servere de baze de date: Acest nivel este format din servere de baze de date SQL, care rulează de obicei pe stații de lucru de înaltă performanță. Conține totul datele bazei de date, metadatele și regulile de integritate referențială necesare pentru ca aplicația să funcționeze. Acest strat este de obicei la îndemâna unui server proxy de rețea corporativă și poate oferi un strat de securitate în plus față de cel al serverului WWW. Netscape Enterprise Server acceptă utilizarea serverelor de baze de date: ODBC, DB2, Informix, Oracle și Sybase. Netscape FastTrack Server acceptă numai ODBC. Pentru mai multe informații despre serviciul de bază de date LiveWire, consultați Partea 3, „Serviciul de bază de date LiveWire”.

Mediul client JavaScript rulează ca parte a clienților WWW, iar mediul server JavaScript rulează ca parte a serverului web Netscape cu acces la unul sau mai multe servere de baze de date. arată mai detaliat modul în care cadrul serverului JavaScript și aplicațiile create pentru acesta sunt integrate în serverul web Netscape.

Cerințe de sistem

A dezvolta aplicații JavaScript care profită de JavaScript atât de client, cât și de server, aveți nevoie de mediul potrivit pentru dezvoltare și publicare. În general, se recomandă dezvoltarea aplicațiilor pe un sistem separat de serverul de publicare deoarece dezvoltarea consumă o mulțime de resurse (porturi de conectare, lățime de bandă, timp CPU și memorie). Dezvoltarea poate, de asemenea, perturba aplicațiile utilizatorilor finali care au fost deja publicate.

Mediul de dezvoltare JavaScript este format din:

  • Utilități pentru autorizarea și compilarea aplicațiilor JavaScript. Aceste utilitare sunt de obicei localizate pe computerul dezvoltatorului.
  • Mașini de dezvoltare cu un server web pentru a rula aplicații JavaScript în curs de dezvoltare.
  • Mașini de publicare cu server web pentru publicarea aplicațiilor dezvoltate. Utilizatorii finali accesează aplicațiile situate pe acest server.

Utilități necesare:

  • Un browser care poate rula JavaScript, cum ar fi Netscape Navigator, inclus cu Netscape Communicator.
  • Un compilator de aplicații JavaScript, cum ar fi compilatorul de server web Netscape.
  • Un editor precum Emacs sau Notepad.

Mașinile de publicare și de publicare necesită următorul software:

  • servere web;
  • Motoare de execuție JavaScript, cum ar fi motorul serverului web Netscape.
  • Capacitatea de a vă configura serverul pentru a rula aplicații JavaScript, așa cum se face în Managerul de aplicații JavaScript care vine cu serverele web Netscape.

În plus, dacă aplicația dvs. utilizează serviciul de bază de date JavaScript LiveWire, veți avea nevoie de:

  • Programul este un server de baze de date relaționale pe mașina dvs. de server de baze de date. Consultați documentația serverului de baze de date. În unele cazuri, va trebui să instalați un server web și un server de baze de date pe aceeași mașină. Pentru cerințele specifice JavaScript pe partea de server, consultați Capitolul 10, „Configurarea bazei de date”.
  • Client de bază de date și software de rețea pe mașina dvs. de server web. Dacă utilizați aceeași mașină atât ca server de baze de date, cât și ca server web, software-ul tipic pentru clientul bazei de date este deja instalat atunci când instalați serverul de baze de date. În caz contrar, trebuie să vă asigurați că clientul bazei de date este instalat pe aceeași mașină cu serverul web, astfel încât să puteți accesa baza de date ca client. Pentru cerințele software client, consultați documentația suplimentară de la furnizorul bazei de date.

Informații de configurare

Această secțiune acoperă informații de configurare pentru utilizarea JavaScript de pe server. Pentru mai multe informații despre configurarea unei baze de date pentru a lucra cu serviciul de bază de date LiveWire, consultați Capitolul 10, „Configurarea bazei de date”.

Conectarea serverului JavaScript

Pentru a rula aplicații JavaScript pe serverul dvs., trebuie să activați motorul de execuție JavaScript în Server Manager făcând clic pe Programe și apoi selectând Server JavaScript. După ce apare mesajul „Activați mediul aplicației JavaScript”. selectați Da și faceți clic pe OK. De asemenea, veți fi întrebat despre restricționarea accesului la Managerul de aplicații. Pentru mai multe informații vezi

NOTĂ: Dacă nu activați motorul de execuție JavaScript, aplicațiile JavaScript nu vor putea rula pe acest server.

Pentru a utiliza atât servlet-urile, cât și LiveWire, trebuie să includeți JavaScript de pe server înainte de a vă conecta Java. Ambele pot fi activate prin meniul programului serverului de administrare. Dacă modificați calea clasei în obj.conf, modificările dvs. se vor pierde dacă activați/dezactivați JavaScript sau Java la nivelul serverului din meniul programului serverului de administrare. O alternativă la editarea directivei classpath în obj.conf este să setați variabila de mediu CLASSPATH pe Unix sau să setați variabila CLASSPATH în setările de sistem pe Windows NT. Dacă trebuie să editați direct obj.conf, salvați fișierul original pentru orice eventualitate. În Enterprise Server 4.0, trebuie să adăugați informații CLASSPATH la fișierele de configurare JVM (jvm12.conf pentru Solaris și NT) prin interfața Enterprise Administration Server.

După ce activați mediul aplicației JavaScript, trebuie să opriți și să reporniți serverul dvs. web pentru ca variabilele de mediu asociate să aibă efect. Dacă nu faceți acest lucru, aplicațiile JavaScript care utilizează serviciul de bază de date LiveWire nu vor funcționa.

Protecție Manager de aplicații

Managerul de aplicații oferă control asupra aplicațiilor JavaScript. Datorită capacităților sale speciale, trebuie să îl protejați de accesul neautorizat. Dacă nu restricționați accesul la Managerul de aplicații, oricine poate adăuga, elimina, modifica, porni și opri aplicații de pe serverul dvs. Acest lucru poate duce, desigur, la consecințe nedorite.

Dumneavoastră (dezvoltatorul aplicației JavaScript) trebuie să aveți drepturi de acces pentru a utiliza Managerul de aplicații pe serverul dezvoltatorului, deoarece îl utilizați pentru a lucra cu aplicația în timpul dezvoltării, totuși, este posibil ca administratorul serverului dvs. web să nu vă acorde astfel de drepturi pe serverul dezvoltatorului .

Dacă activați motorul de execuție JavaScript în Server Manager, promptul vă va întreba dacă restricționați accesul la Application Manager. Selectați Da și faceți clic pe OK. (Da este valoarea implicită.) Oricine încearcă să acceseze Managerul de aplicații va trebui să introducă numele de utilizator și parola Server Manager pentru a putea utiliza Managerul de aplicații și aplicația exemplu dbadmin. Pentru informații suplimentare, consultați ghidul administratorului pentru serverul dvs. web.

Dacă serverul dvs. nu utilizează Secure Sockets Layer (SSL), numele de utilizator și parola Managerului de aplicații sunt trimise necriptate prin rețea. Prin interceptarea acestor date, puteți obține acces la Managerul de aplicații. Dacă utilizați aceeași parolă pentru serverul dvs. de administrare, hackerul va câștiga controlul și asupra acelui server. Prin urmare, se recomandă să nu utilizați Managerul de aplicații în afara unui proxy decât dacă utilizați SSL. Pentru informații despre cum să conectați SSL la server, consultați ghidul administratorului pentru serverul dvs. web.

Andrei Sumin: Bună ziua, mă numesc Andrey Sumin, lucrez la Mail.Ru. Mai este puțin timp suplimentar, așa că am pregătit un mic bonus - doar pentru cele douăzeci de minute rămase. Vă voi arăta capabilitățile motorului nostru de șabloane, pe care l-am creat pentru a obține cifrele de care avem nevoie.

Înainte de asta, aveam un motor de șabloane complet în C. Era destul de unic. Așa că ne-am dorit foarte mult modele ca acesta în care să putem folosi JavaScript.

Mai jos puteți vedea în ce se transformă json.name pe server.

Nu mă voi concentra pe asta acum. În partea principală a raportului, voi vorbi despre ceea ce compilăm, de ce și de ce. Doar că acum ofer construcțiile de bază care pot fi folosite pentru a obține o valoare dintr-un hash. Vă puteți distra puțin „scăpând” de această valoare.

Sigur = adevărat. Mai jos puteți vedea codul compilat. Prin „safe=true” puteți vedea imediat că, de exemplu, „try catch” a dispărut.

Construcțiile de care are nevoie orice motor de șablon sunt „dacă” și, în consecință, „alege”. Dar, de obicei, se folosește forma „dacă altfel”, care este foarte necesară pentru dezvoltator. Dar dacă doriți XML valid, atunci, din păcate, singura modalitate este „alege”.

Iată codul la care se compilează.

Desigur, se folosesc bucle. Unde am fi fără cicluri? Buclă printr-o matrice, buclă printr-un hash.

Motorul nostru de șabloane „decupează” totul între etichete în mod implicit.

Mi-e teamă că ar putea fi cei aici care nu sunt familiarizați cu aceste lucruri. Dar în spațiu html este un simbol semnificativ. Prin urmare, este indicat să indicați că doriți să aveți un spațiu în acest loc. Da, există lucruri atât de specifice.

Fest:script este necesar pentru a putea executa un cod JavaScript chiar în mijlocul motorului de șablon.

Acum voi încerca să fac mici demonstrații, astfel încât să puteți vedea la ce duce asta. Iată, am pregătirea de ieri. Acesta este un server HTTP obișnuit pe Node.js.

(Vorbitorul arată demonstrația.)

Pornește un server. Aici luăm șablonul. Desigur, vă voi arăta șablonul. Am câteva dintre demonstrații comentate aici. Luăm un șablon, acesta ar trebui să se transforme într-o funcție JavaScript „șablon”. Aici folosim acest șablon de o mie de ori. Întrucât subiectul principal al raportului meu sunt cifrele, suntem interesați să măsurăm performanța acestuia în unele situații stresante. Mai jos, în consecință, afișăm rezultatele pentru acest model.

Să aruncăm o privire mai atentă. Primul model este o buclă de zece mii de iterații.

Să-l punem aici html mai bun, va fi mai interesant. Produce un interval, în interiorul căruia scoatem valoarea „hello” din hash-ul intrării în șablon și facem concatenarea cu data curenta. Concatenarea șirurilor este o operație destul de costisitoare. Toate acestea se vor întâmpla de zece mii de ori. În plus, vreau să vă arăt și că șablonul în sine va fi executat de o mie de ori.

Să încercăm să lansăm...

Acum vor exista numere bazate pe Node.js. V8 este folosit de Node.js. Vedem zece mii de astfel de concatenări. Nu-ți face griji, le scot doar pe cele mai recente în browser, altfel aș avea probleme de memorie în browser. 10 mii de concatenări efectuate de o mie de ori. Ne-au dat cinci secunde. Aceasta înseamnă că au existat 10 mii de concatenări la un moment dat și ne-a luat 5 milisecunde pe Node.js pe server.

Putem vedea cât timp durează în browser (dacă trimitem același șablon direct în browser).

Numărul este ușor diferit. Putem, de fapt, să ne uităm în continuare la alt browser. Suntem interesați de motorul de șabloane JavaScript. În general, puteți vedea deja ce se va întâmpla. Aceasta este Opera. Aceasta înseamnă că ar trebui să aibă aceleași lucruri pe client și pe server. Există aproape un minut - 40 de secunde, după părerea mea. În orice caz, chiar dacă va fi foarte număr mare, trebuie împărțit la o mie.

Poftim. 39 de secunde. Aparent, și-a petrecut restul timpului pe randarea în browser în sine. Chiar și atunci când obținem numere în browsere diferite care diferă de mai multe ori (poate chiar un ordin de mărime) - tot țineți cont de faptul că toate acestea trebuie împărțite la o mie. Aceasta înseamnă că o trecere a durat 39 de milisecunde.

Pentru șablon, folosim acest motor de șablon pe client pentru proiectele care sunt utilizate - acestea pot fi versiuni mobile proiecte pentru versiuni mai vechi de Android și nu avem probleme de performanță. Din păcate, nu pot să-l arăt în IE acum, pentru că mai am un Mac. Dar există câteva nuanțe interesante.

Avem un motor de șablon implicit cu „escaped” activat. Acest lucru va fi discutat în partea principală a raportului. Dacă știm că datele noastre cu siguranță nu sunt introduse de utilizator, atunci „escaped” poate fi dezactivat.

Să vedem ce se întâmplă cu numerele. Este pe server acum. Acesta este V8 pe server prin Node.js.

Deci, se pare, am greșit undeva. Aici este „salvează adevărat”. Acest lucru nu ar trebui să aibă niciun efect. Ei bine, da, desigur - serverul trebuie repornit. Sunt încă obișnuit să lucrez cu clientul, unde apăsați Ctrl+S+F5.

Aici, de fapt, este diferența.

„escape html” necesită mult timp. Am luat asta pentru a demonstra ordinea problemelor pe care trebuie să le confruntăm.

În ceea ce privește „salvare”, în slide-ul anterior, fiecare expresie JS pe care o face designerul de layout este înfășurată implicit într-un „try catch”.

De fapt, nu costă foarte mult, cel puțin într-un V8.

Nu este mare diferență. Deși, de fapt, „captura de încercare” a fost înfășurată, după cum înțelegeți, într-o mie până la zece mii. În general, există o mulțime de operațiuni - 10 milioane. ÎN browsere moderne acest lucru se face foarte repede, și la motoarele moderne.

Dacă aveți sugestii cu ce să-l încărcați, o puteți exprima. Sa incercam. Poate vom găsi chiar ceva care poate fi îmbunătățit.

Acum al doilea exemplu interesant, fără de care nu am putea trăi. Nu este nou. L-am împrumutat într-o anumită formă de la XSLT. Voi vorbi și despre asta. Acum - o demonstrație. Totuși, poate cineva va veni la începutul raportului.

Avem un șablon separat care scoate un interval. În interiorul intervalului avem un apel (aici, l-am evidențiat) - fest:get. Înseamnă să afișați un bloc cu numele „cuvânt” în acest loc. Și mai jos este definiția că acesta este conținutul acelui bloc și, respectiv, este egal cu cuvântul „cuvânt”.

Aici. Afișăm conținutul acestui bloc. Puteți vedea din șablon că este pur și simplu inclus în acest fișier, care spune să afișați un interval cu acest bloc. Nimic altceva nu se întâmplă deoarece „dacă” nostru returnează false (cel puțin condițiile din „dacă” returnează false).

Este clar ce s-a schimbat? Acesta este un exemplu că în browser, de fapt, aceleași șabloane sunt procesate exact în același mod. Aceasta este aceeași moștenire care se găsește în toate motoarele de șabloane moderne (și nu atât de moderne). Foarte aproape, în opinia mea, de „Django” - este aproape la fel.

Vreau să spun că această sintaxă XML este „zahăr sintactic” pentru designerii de layout. Unii dintre oamenii noștri care sunt familiarizați cu XSL, când au văzut această sintaxă, au început să scrie în ea ca limba lor maternă. Dar asta a dus la probleme. Aici, avem o „valoare de festival”, pe care o afișez aici. Iată, să spunem - „valoarea festivalului”.

Au venit și au întrebat dacă are un atribut „format” pentru a-l putea forma imediat cumva în „valoarea festivalului”. La care am răspuns: „În acest moment, uită de XSL. Ai JavaScript în interior”. Inclusiv cam aceeași sintaxă. Este conceput exclusiv pentru a se asigura că sarcinile obișnuite duc la foarte solutii rapide prin viteza. Prin urmare, acolo nu există „clopote și fluiere” speciale. Dacă sunt clopote și fluiere, trebuie să fie o decizie conștientă dezvoltator specific. Trebuie să fie exprimat în JavaScript.

Iată o sarcină mai interesantă. Să presupunem că avem o bibliotecă JavaScript... Această funcție poate inflexa cuvinte. La intrare, primește un număr și o serie de cuvinte care trebuie refuzate. Îl conectăm în această linie. Aceasta înseamnă că în acest moment acest JavaScript va fi executat pe server și va crea această funcție.

Creăm o serie de cuvinte. Iată o mică matrice care va scoate rezultatul de la zero la nouă, cum se va comporta această funcție cu astfel de parametri de intrare.

Iată funcția cuvântului declinat.

Acest lucru în sine nu este foarte interesant, dacă nu pentru următorul exemplu.

Acum este un șablon care generează html pentru browser. Atenție: acesta nu mai este „fest include”, ci „fest insert”. În acest moment inserăm acest JavaScript. Browserul îl va primi exact ca program JavaScript.

Aici avem exact același exemplu. Aici funcția noastră a ajuns la client și o putem folosi pe client.

Cel mai mare bonus pentru care am luptat a fost că aceleași biblioteci, șabloane și programe JavaScript puteau fi folosite pe client și server. Anterior, acest lucru era imposibil tocmai pentru că era lent și de neînțeles. În cazul în care cineva își amintește primele încercări de a folosi JavaScript pe server - a fost, după părerea mea, un fel de IDE. Jagser, cred că se numea.

Replica din sală: Aceasta este Aptana?

Andrei Sumin: Da, Aptana. A fost, desigur, un eșec total. Am încercat sincer, am încercat sincer, dar am renunțat. Odată cu apariția motoarelor separate de la browsere diferite, odată cu apariția competiției în care concurează între ei la performanță, avem capacitatea de a folosi JavaScript pe server.

Ai întrebări despre exemplele mele?

Replica din sală: Pot vedea codul compilat?

Andrei Sumin: Da. Ne putem uita la codul compilat. Iată codul șablonului compilat. Aici unele funcții de service sunt pe primul loc, desigur. După cum am spus, e nevoie de evadare.

Iată, de exemplu, ciclul nostru. Așa că am evidențiat-o. Să încercăm să o aducem mai aproape. Aici este aceeași bună ziua + dată. După cum am promis, avem totul în „try catch” în mod implicit. Deci, dacă dai dintr-o dată peste un designer de layout care nu înțelege cu adevărat JavaScript, cel puțin nu va sparge nimic pentru tine. Escape html - sincer, fără a înșela.

Replica din sală: Ai pe cineva în echipa ta care înțelege JavaScript?

Andrei Sumin: Da. Am mai mult de trei sau patru (poate chiar cinci) oameni în echipa mea care știu să „gătească” scripturi java. Ei înțeleg ce este și cum să o „gătească”. Un pericol mult mai mare este o „traumă” arhitecturală a JavaScript - așa-numitul cuvânt „var”. Daca nu ai declarat, vei avea probleme. Pe server, aceasta este de fapt o scurgere de memorie, deoarece implicit variabila va ajunge în lista globală și va rămâne acolo, cel puțin până când contextul este reîncărcat.

Dar avem modul Straight, care nu permite acest lucru. Motorul actual de șablon funcționează implicit cu modul drept. Am încercat să provoc scurgeri de memorie - nu a funcționat.

Să începem povestea despre rularea JavaScript pe server.

De ce este necesar acest lucru?

Desigur, prima întrebare care apare atunci când vorbim despre JavaScript pe server este întrebarea „de ce?”. Am programat mult în JavaScript, îmi place foarte mult. Dar acest lucru nu este suficient. Încă trebuie să fim ocupați.

În companiile mari (am lucrat în mai multe companii mari) există o astfel de caracteristică. Avem o mulțime de dezvoltatori backend puternici. Ei știu să scrie cod și știu multe despre servere. Prin urmare, lăsați-i să scrie un motor de șablon pentru designerii de layout (cu excepția cazului în care trebuie să folosească unul special). Acest lucru cauzează o mulțime de probleme. Acești dezvoltatori au propriile lor probleme, proprii șefi, trebuie să facă ceva. Când au venit la ei cu solicitări de genul „să terminăm ceva, ne lipsește ceva”, chiar nu mi-a plăcut.

În același timp, există o a doua caracteristică care este deosebit de relevantă acum. Există o mulțime de oameni care cunosc JavaScript. Mai exact, am o mulțime de oameni care știu JavaScript. Și motorul meu actual de șabloane este în C, dar nu am o singură persoană sub comanda mea care să cunoască C.

Bineînțeles, așa cum am spus, șablonul revine clientului. Ne-am gândit la toate acestea, începând cu proiectul „Mail”. Proiectul Mail nu se poate lipsi de șabloane din partea serverului, deoarece este nevoie de o pornire rapidă. Concurenții nu dorm. Nu se poate face fără șabloane pe partea clientului, deoarece se folosește Ajax, totul trebuie să fie rapid și aici. Utilizatorul trebuie să fie mulțumit pentru că este foarte ușor să treci la concurenți.

În același timp, am ajuns să avem o situație în care avem șabloane pe client și șabloane pe server, logica este aceeași, dar șabloanele sunt diferite. Dublarea codului, multe probleme. Nu este clar ce să faci în privința asta. Există într-adevăr o mulțime de greșeli.

Ce ne-am dorit?

După cum am spus deja, pe lângă JavaScript, am scris multe și în XSL. Acesta este, de asemenea, un motor de șablon foarte bun, poate cel mai puternic. Dar nici fără „traumă la naștere”. Deși sunt necesare unele dintre capacitățile sale.

În plus, dacă avem XSL, unul dintre dezavantajele sale este că nu are încorporat niciun fel de limbaj complet algoritmic. Când vrem să resortăm matricea acolo, aceasta este încă o problemă care se poate rezolva. Dar când vrem să mergem acolo „regulat”, în XSL este un adevărat iad.

Deci ne-am dorit ce e mai bun dintre aceste două lucruri?

Iată exemplul pe care ți l-am arătat, seamănă foarte mult cu „Django”. Declarăm un bloc. Aici avem „titlu”. Conținutul său este determinat imediat - că este „Mail.ru”. Dacă conectăm acest șablon așa cum este pe pagină, atunci afișăm „titlu” cu titlul „Mail.ru”. Toate proiectele care sunt pe Mail.ru se pot conecta și au un singur antet.

Dar avem proiectul „Mail”. Desigur, ne dorim totul la fel ca în alte proiecte, doar titlul este diferit. Nu scrie alt șablon din cauza asta! Vreau doar să redefinim o parte din el.

JavaScript în sine.

Ne dorim foarte mult să putem lucra cu datele de intrare într-un limbaj complet din punct de vedere algoritmic. Există o astfel de construcție ca „script fest”. Puteți face ceva în el în mod specific în JavaScript, iar mai jos, folosind „valoarea festivalului”, de fapt, îl puteți desluși.

Acest șablon se va afișa în Mail.ru.

Motorul de șablon în sine.

De fapt, am avut multe dezbateri despre sintaxa XML. Sintaxa XML este redundantă - este stupid să argumentezi asta. Cu toate acestea, sarcina noastră principală a fost să învățăm cum să „gătim” JavaScript pe server. Prin urmare, nu am vrut să rezolv simultan problemele „să venim cu sintaxa în ea”, „să venim cu evadarea în ea”, „să scriem tot felul de plugin-uri pentru IDE-ul în el”. Nu am vrut să rezolv asta. Prin urmare, am luat XML și am venit cu suport IDE scurt.

Orice IDE care se respectă vă va spune fără nicio setare că XML-ul dumneavoastră nu este valid. Iar validitatea șabloanelor XML ne oferă automat valabilitatea html-ului de ieșire. Iată validarea din cutie.

În plus, toate IDE-urile au evidențiere și tabulare automată. Nu am vrut să mă deranjez.

XML are și asta în mod implicit un lucru bun, ca spații de nume. Aceasta este extensibilitatea.

Avem un motor de șablon, dar nu poate face mare lucru. Ai proiecte reale. Dintr-o dată ai nevoie de multilingvism. „Cosutul” în șablonul implicit al festivalului este oarecum ciudat. Se va „umfla” și va deveni insuportabil. Și dacă declari, să zicem, spațiul de nume al proiectului tău, atunci poți „intercepta” acest eveniment în compilator și să-l procesezi în felul tău. Să presupunem că puteți avea anumite spații de nume fest și Mail.ru.

De-a lungul anilor, am avut o mulțime de instrumente pentru a lucra cu XML. Când compilam dintr-un șablon de festival în XML, aveam o gamă largă de opțiuni de utilizare. Ca rezultat, am folosit un parser SAX, dar nu este un fapt că mă voi opri aici.

Conversie XML în XML

Din nou, am menționat că șirurile noastre de ieșire nu sunt foarte simple. XML este un limbaj destul de liber. Prin urmare, nu am vrut cu adevărat să mă angajez în „scăpare”. Când aveți structuri de control la fel ca în XSL, aproape toate problemele dvs. de „scăpare” dispar. În plus, există lucruri suplimentare, cum ar fi CDATA, care vă permit să „scăpați”.

Implementarea

Când am decis cum ar trebui să arate șablonul (am înțeles aproximativ de ce avem nevoie banc de testare, astfel încât să înceapă să funcționeze), am început să implementăm compilatorul XML în sine în JavaScript.

Aceasta a fost o experiență de programare în pereche destul de neobișnuită pentru mine. Eram chiar sigur că programarea în pereche dă rezultate foarte bune, mult mai bune decât programarea unică.

Dar în special în această problemă, sa întâmplat invers. Am luat șablonul, am înțeles care ne dorim să fie rezultatul și am început să compilăm. Eu am făcut versiunea mea, iar Kostya a făcut versiunea lui. Ne întâlnim o dată pe săptămână și, aproximativ vorbind, măsuram numere. Adevărat, numerele lui au fost întotdeauna puțin mai rapide.

Structură vs Funcție

Am ales două în principiu abordări diferite. Am decis să compilez XML într-o structură. Și Kostya a compilat-o direct într-o funcție. La început nu mi s-a părut foarte sigur.

Ca să înțelegeți, compilarea într-o structură este ceva ca această matrice.

Hashurile înseamnă o acțiune, iar șirurile pot fi fie scoase direct către client, fie se poate face ceva cu ele.

Pentru clarificare. Primul hash - "action":"template" înseamnă că șablonul începe. Nu trebuie să faceți nimic cu a doua linie; aceasta poate fi trimisă direct către client. A treia linie înseamnă că a patra linie trebuie trecută val, și rezultatul val adu-l deja clientului.

Sau, de exemplu (probabil va fi mai clar), luați în considerare opțiunea cu „dacă”.

Prima și a doua linie sunt aceleași ca pe diapozitivul anterior. A treia linie înseamnă că trebuie executată următoarea expresie. Dacă este adevărat, atunci, în consecință, trebuie să scoateți „adevărat”. Dacă este fals, atunci ar trebui să apară „false”.

De fapt, aceasta este inspirată de o tehnică destul de cunoscută care este folosită în aproape toate calculatoarele - aceasta este o notație inversă a utilizatorului. Am vrut să mă joc cu ea cumva, dar toate acestea s-au dovedit a fi inutile. Șabloanele reale s-au dovedit a fi mult mai simple.

Totul este clar cu implementarea într-o funcție. Doar că, din cauza unor condiții, variabila originală, care este setată la un șir gol, începe să fie concatenată.

Acesta este rezultatul pe care ne-am dorit.

Acesta este unul dintre proiectele noastre principale. Desigur, când mă gândeam la un motor de șablon, a trebuit să mă gândesc la acest proiect. O listă de litere cu un număr suficient de dosare.

Voi fi sincer: prima implementare pe care am făcut-o a rezolvat această problemă în 200 de milisecunde.

Eu și Kostya ne-am dat cu capul, după părerea mea, timp de o lună sau o lună și jumătate. Au venit după weekend, iar unul a spus: „Și eu am 180!” Al doilea a răspuns: „Și am 150!” Și așa mai departe și așa mai departe. De fapt, la un moment dat am renunțat pentru că mi-am dat seama că nu voi ajunge din urmă. Am început să facem o implementare cu o funcție, a câștigat. Când în sfârșit am „lings” totul până la sfârșit, ne-a luat 3 milisecunde pentru a finaliza această sarcină.

Lista de litere a fost desenată în 3 milisecunde. Transformarea este cam așa, este cât mai aproape de cele mai simple construcții JavaScript. „Pentru” – în „pentru”, „dacă” – în „dacă”. Alegeți este „dacă() altfel”.

A trebuit să ne luptăm puțin cu fest:set, pentru că mi-am dat seama că nu putem continua să trăim fără această override. De asemenea, nu este foarte greu de făcut. Când executăm funcția șablon pentru prima dată, obiectul „set” este mai întâi creat. Pe măsură ce întâlnește blocuri XML „set”, rescrie funcția, care, de fapt, redefinește conținutul acestui bloc.

Prin urmare, dacă există o mulțime de „seturi”, atunci când se execută un șablon care va returna XML, doar ultimul dintre ele va fi executat și nu toate. Acest lucru a dat și o mică creștere.

Următoarele au dat un efect foarte interesant. Nu ne-am deranjat prea mult cu prima implementare. Când au fost 200 de milisecunde, noi, în general, nu am văzut asta. Dar mai întâi l-am compilat în această structură. Avem HTML sursă, care a fost pur și simplu compilat într-o concatenare linie cu linie.

Când ne apropiam de trei milisecunde, am folosit un simplu „obișnuit” în șablonul compilat pentru a înlocui acești „plus-egal” cu o singură linie - de fapt am obținut o cifră decentă - plus 30% din performanță.

Să vorbim din nou despre siguranță.

Siguranță

Prin securitate mă refer nu numai la XSS: cu siguranță avem nevoie de motorul de șablon pentru a-l minimiza din cutie. Mai mult, sper că îi exclude „din cutie”. Dar ar trebui să existe o „prindere de încercare” dacă dintr-o dată un designer de layout neglijent ia proprietăți fără definiție (engleză: nedefinit).

Prin urmare, în mod implicit totul este în încercare de captură. În plus, conform testelor noastre, este „gratuit”.

Aceasta este o evadare. Există și escape JavaScript, escape HTML. Datele utilizatorului, astfel încât să nu existe acces.

Din nou, după cum am văzut, aceasta este cea mai „scusitoare” operațiune din motorul nostru de șabloane.

Desigur, folosim „modul strict” pentru a evita scurgerile de memorie.

Dacă un designer de layout vede dintr-o dată ceva, va observa imediat în timpul dezvoltării că a greșit ceva. Și în producție, vom începe să repornim serverele și, între reporniri, vom afla ce s-a întâmplat de fapt.

După cum am spus deja, compilația implicită este doar „try catch” plus „escape”.


Integrare

Am primit numerele pe care le-am dorit. Sau, cel puțin, au primit niște numere decente cu care nu este păcat să vină.

Următorul punct interesant. În compania noastră, avem cel puțin aceste limbi. Sunt sigur că mai sunt multe. Dar acestea sunt cele pe care le-am întâlnit.

Acesta este „C” - avem un server HTTP în „C” și este scrisă multă logică în el. Perl: Cele mai multe e-mailuri sunt scrise în Perl. Unele proiecte sunt scrise în Python. Nu avem Node.js în producție, dar îl folosim și în dezvoltare, desigur, trebuie să trăim cu el.

S-ar părea că atunci când adăugăm un V8 acestui soi, nu vom face decât să înrăutățim lucrurile. Dar când am adăugat V8 la toate aceste tehnologii în unele proiecte... De fapt, nu este dificil pentru asta. Am nevoie de un V8 (este unul acolo) API-ul Google) a anulat aceste trei funcții pentru înregistrare.

V8 este doar o bibliotecă în sine, nu poate face nimic. Aceasta este o bibliotecă care ia ceva ca intrare și dă ceva ca ieșire. Desigur, atunci când ceva se întâmplă în interiorul tău, vrei să-l comunici lumii exterioare. Acest fest_log este la discreția tehnologiei. El poate raporta fie consolei, fie browserului, fie prin scrisoare sau SMS administratorului de sistem că ceva nu este în regulă în interiorul V8. Și V8 primește această funcție intern și poate interacționa cumva cu ea și prin ea cu lumea de afara.

Fest_file este, desigur, modelat. Bate pe fișiere, „include”, „inseră” și așa mai departe și așa mai departe. Deci, atunci când V8 colectează și compilează fișiere, trebuie să se ocupe de „include” și „inserare”. Prin urmare, mediul extern trebuie să ofere lui V8 capacitatea de a citi fișierul.

Dirname este un lucru atât de mic. Când doriți să citiți un fișier, aveți nevoie de ceva pe care să vă bazați. Acesta este directorul fișierului JavaScript executabil în prezent. Aceste trei modele sunt suficiente pentru ca V8-ul să funcționeze.

S-au întâmplat următoarele. Avem o grădina zoologică întreagă de tehnologii pe serverul nostru back-end. Dar există un proiect care folosește fest pe server. Există un proiect care folosește fest pe client. Există un proiect care folosește fest pe client și server. Sintaxa este aceeași peste tot, iar designerii de layout migrează între proiecte, nu există probleme cu asta. Desigur, avem integrarea browserului din cutie.

Fest se compilează în construcții JavaScript primitive, care (sunt sigur) sunt acceptate chiar și de Explorer 5. Pur și simplu nu era unde să încerce, îmi pare rău.

Lucrul cu utilizatori reali

Deci, avem o implementare și încă vrem să ajungem la utilizatori, să aflăm cum va funcționa totul pentru ei. Am venit la Igor cu această implementare și am spus că rulările noastre de testare se potrivesc în trei milisecunde. El a răspuns: „Dansează cum vrei – și apoi în patru picioare”.

Trebuie să înțelegeți că producția este, pe lângă transformare, și alte date care trebuie obținute și făcut ceva cu ea. Și 4 milisecunde este totul.

Bucătăria noastră internă a fost deja folosită aici, este puțin probabil ca cineva să aibă asta. Dar, din păcate, sa dovedit a fi foarte important să ratezi.

Serverul nostru HTTP este scris în C, îl numim Light. Când primește date de la serverul back-end, le stochează într-un hash plat. De fapt, aceasta este o opțiune primitivă. Ar trebui să fie ușor de citit. Pentru orice eventualitate, permiteți-mi să clarific că aceasta este o listă de litere. Prima linie înseamnă că lungimea sa este de cinci, a doua linie înseamnă că prima literă are titlul „scrisoare”, iar a treia linie înseamnă că nu a fost citită.

Desigur, când vorbim despre JavaScript, vrem să vedem V8 așa în interiorul lui.

Cumva trebuie să introducem asta în V8. Am încercat o mulțime de opțiuni. Am trecut în revistă tot felul de Binding, PerlOuI și soluțiile noastre - după părerea mea, am suferit aproximativ două săptămâni. Iată opțiunea pe care am încercat-o cu siguranță - aceasta este o soluție la problemă prin API-ul V8.

Am încercat, dar, din păcate, nu a fost posibil să furnizez codul în C. Chiar există multe. Voi încerca să explic în cuvinte.

Prin API-ul V8, puteți face acest lucru: dacă scrieți JSON în JavaScript, în acel moment V8 vă accesează codul C. Codul C în acest moment poate returna ceea ce consideră necesar. Poate scrie JSON.name. Aceasta va fi în două abordări - prima dată va accesa JSON, iar a doua oară va accesa numele. Este prea lung.

A doua opțiune este JSON.parse. Când ridicați contextul V8, apoi în „C” colectați o linie care este exact ca JSON. Îl trimiteți în context și, direct în context, suprapuneți V8 JSON.parse pe el din cutie. În consecință, deja în context aveți un hash care poate fi trimis la șablon. Acest lucru sa dovedit a fi, de asemenea, lent.

Cel mai varianta rapida- aceasta este doar a treia opțiune. Voi încerca să vă arăt o bucată de cod C de la el.

Aici ai a doua linie. Acesta este doar un șablon. Ta Funcția JavaScript, în care este compilat fest. Se așteaptă ca intrare JSON. Colectați o astfel de linie, un apel la această funcție, iar primul și singurul său argument este JSON care trebuie utilizat. Dați comanda să o faceți.

Cifrele nu erau prea bune. Cu o limită de patru milisecunde, dintre care două sunt transformări. Le-am măsurat separat. Pregătirea datelor a durat patru secunde.

Cauți acum: s-ar părea că sunt necesare patru milisecunde pentru a pregăti datele - și ce? Și asta reprezintă 67% din transformare.

67% din timpul nostru este petrecut pregătind date pentru a genera acest html. Am avut sarcina de a îndeplini aceeași capacitate pe care o avem acum. 6 milisecunde în loc de 4, e aproape. Dar tot era păcat. De fapt, în acest moment aproape că am abandonat ideea.

Dar am găsit totuși puterea să iau hașul de care îți amintești. L-am luat sub formă de text și am venit acasă. Sincer să fiu, nu-mi amintesc codul acum. Dar eu sunt din tip de text a fost cumva transformat în JSON de către Node.js.

Am venit la Igor cu aceste numere și mă așteptam să aud de la el: „Tu, desigur, ești grozav și Node.js nu vom scrie în Node.js. Să ne evaluăm în continuare gândurile. Dar am auzit absolut contrariul. Dacă este posibil în Node.js, de ce nu îl putem folosi? În acel moment mi-am dat seama că vom rezolva această problemă.

Ce am făcut? Să revenim la datele pe care le avem în serverul HTTP.

De fapt, avem deja toate datele pe serverul HTTP. Așa că am făcut următorul truc. În loc să convertească datele, V8 a „redirecționat” o funcție care ar prelua aceste date folosind o cheie.

Am eliminat imediat orice conversie care ne-a luat 4 milisecunde. A mai rămas timp să înaintezi. Dar s-a dovedit că acest timp este de 1 milisecundă. Cu o limită de 4 milisecunde... Vă reamintesc că aceasta este o listă de litere. Am primit milisecundele pe care le căutăm. Utilizatorii reali aveau voie să facă acest lucru. Nu că ar fi văzut-o, dar situația este standard.

Am luat unul dintre servere și l-am oprit de la echilibrare. Au instalat acolo întreaga infrastructură, care este folosită pentru a trage o listă de litere. Am „eșantionat” câteva dintre solicitările reale ale utilizatorilor reali cu date reale și o listă reală de scrisori. Tocmai au trimis datele la acest server (duplicat). Avem aici rezultatele testelor de sarcină de 30 de ore.

Da, apropo, aceste rezultate au fost afișate de un nucleu, nu de server, vreau să notez. Serverul a procesat 10 milioane de accesări în 30 de ore. Timpul mediu de transformare a fost de 1,6 milisecunde. Nu este vorba că serverul a fost mai rapid. Doar că utilizatorii reali au setări diferite... Am testat totul pe 25 de litere, iar în unele locuri au fost pur și simplu mai puțini utilizatori reali. Figura de mai jos arată doar că jumătate de procent, de exemplu, se încadrează de fapt în zece milisecunde. Dar, se pare, au doar 200 de litere în setări.

Cred că nu este nevoie să explici direct cifrele. Aici puteți vedea că majoritatea au mai puțin de două milisecunde. 90% dintre solicitări sunt mai mici de două milisecunde.

Totuși, trebuie să ajungem la utilizatori reali, la cei adevărați, astfel încât să poată vedea cu ochii lor, chiar dacă nu le pasă.

Când Igor și cu mine am venit la Ermakov cu numerele primite (pe atunci era deputat director tehnic), am spus: „Testele de încărcare sunt bune, cifrele sunt bune, sarcina este reală. Vrem să lansăm acest lucru pentru utilizatori.” Ca orice companie mare, avem câteva proiecte care sunt în așteptare. Se pare că ar trebui să le faci, dar se pare că nu ar trebui. Spun: „Să facem unul dintre aceste proiecte pe V8 la festival, atunci este în regulă să uităm de acest proiect în același mod în care am uitat Anul trecut. Dar dacă totul merge bine, vom obține un lucru funcțional pe care să putem construi.”

Igor s-a uitat la mine, s-a uitat la numere și a spus: „Numerele sunt bune, dar chiar vrei un V8 în producție?” Eu spun: „Vreau”. El a răspuns: „Atunci, începeți de la pagina principală. În caz contrar, acești „muci” vor continua să fie mânjiți. Era o pagină. Amenajarea a durat trei zile. Am alocat din nou unul dintre serverele front-end și am lansat acolo jumătate din încărcarea normală. Am primit un consum de resurse de procesor de trei ori mai mare decât front-end-ul vecin, care acum funcționează pentru utilizatori.

Părea un eșec total. De fapt, am făcut o greșeală foarte mare (vă voi arăta unde mai târziu). Dar asta ne-a oferit mai multă optimizare. Totul a fost foarte trist, pentru că eram atât de cufundați în această sarcină încât aveam tot codul de motor șablon în cap. Aș putea să-l rezolv în minte fără să apelez la IDE. Nu am înțeles unde am putea pierde atât de mult în timp, pentru că în toate testele anterioare totul a fost bine.

Am pierdut de șase ori față de serverul actual.

Nu este prima dată, după cum se spune. Au început să privească. Pagina principală ocupă 165 kiloocteți. Dintre acestea, V8 generează 65 de kiloocteți. Au mai rămas 100 de kiloocteți. Avem tehnologia RB înăuntru. Ca să înțelegeți, pagina principală este încă o vitrină a altor proiecte. Prin urmare, RB este un mijloc de livrare a datelor din aceste proiecte către pagina principală. RB este trimis către serverul HTTP, în general, sub formă de html. Nu este nevoie să-l modelați. Dacă este necesar, atunci RB face acest lucru intern. Prin urmare, se întâmplă următoarele.

Avem tehnologie RB. „Vorbește” cu serverul HTTP, serverul HTTP returnează rezultatul la V8. V8 concatenează acest lucru cu datele sale și îl trimite înapoi. Încă o notă pentru cei care nu au citit nimic despre V8. El păstrează totul în interiorul său în utf-16. Asta înseamnă că noi... Și a noastră, desigur, era de la utf-8. Utf-8 utf-16 înapoi la utf8.

Așa arăta codul compilat inițial într-o formă foarte simplificată.

Avem niște sfoară. Rezultatul muncii lui RB este concatenat cu această linie și apoi este concatenat cu rândul următor V8.

Se pune întrebarea: dacă nu facem nimic cu RB, de ce să-l dăm deloc V8-ului și să cheltuim resurse pentru el? Așa că am făcut un mic hack. Încă două funcții au fost transmise de la C. Aceasta este o funcție push Din fericire, pagina noastră de pornire este solidă. Prin urmare, nu este nevoie să suferi cu „set” și „get”.

Nu te concentra pe asta. Dacă cineva se uită la el în detaliu, vei înțelege despre ce vorbesc. Acolo modelarea este continuă, sau mai degrabă liniară. Odată ce șablonul a completat o „piesă”, știm sigur că acesta poate fi dat utilizatorilor.

Ni s-a întâmplat următoarele: biblioteca V8 a generat o parte dintr-un șir conform logicii sale și a trimis-o direct la serverul HTTP. Îl poate oferi imediat clientului. Apoi, în mod logic, trebuie să dai o piesă de la RB. Nici măcar nu primim această bucată. Îi spunem imediat serverului HTTP: „Ia această bucată și dă-o direct clientului - nu avem nevoie de nimic de la el”. Am primit încă 30%. Dar, de fapt, pierderea a rămas de patru ori.

Am bănuit că ceva nu e în regulă. Am luat această încărcare, numărul de accesări pe care le trimitem la serverul de testare. L-am înmulțit cu numărul de servere pe care le-am „strâns” în prezent și am primit acest număr de accesări pe zi.

440 000 000

Și conform tuturor contoarelor TNS, avem atât de multe accesări pe zi.

110 000 000

Am început să ne uităm la jurnalele și am descoperit un lucru amuzant: pentru fiecare cerere utilă, avem patru solicitări să punem ceva în jurnale. Noi, bucuroși, am ajuns în exact resursele de care aveam nevoie. Această imagine demonstrează acest lucru.

Deja pe un server care rulează, de ceva timp am avut ocazia să comutăm între motoarele de șabloane. Graficul de sus este memoria. Memoria V8 are nevoie, desigur, de puțin mai mult. O defecțiune a memoriei este doar o trecere la vechiul motor de șablon. Graficul de jos este doar o „piatră”. Nu există modificări la acesta. Am lansat totul pentru utilizatori.

Acum întreaga pagină principală a Mail.ru este servită prin V8.

V8 generează în prezent 65 de kiloocteți de date. Poate că astăzi este puțin mai mult - am petrecut încă două săptămâni pregătind raportul. Timpul de care are nevoie biblioteca pentru a genera aceste date este de o milisecundă. Plus 40 de megaocteți pe context, ținând cont că numărul de nuclee de pe server ajunge la 8, nu știu, sau la 16. Acest lucru, în principiu, nu este foarte enervant, nu există probleme cu el.

Este aproape o poveste de succes. Igor Sysoev este prezent aici. Oricine s-a gândit vreodată la V8 pe un server ar trebui, desigur, să citească articolul său despre problemele V8.

Daca gresesc, sper sa ma corecteze. Din câte îmi amintesc, despre asta este vorba. În V8, în primul rând, contextul nu este ridicat instantaneu. Dacă vorbim de proiecte reale, atunci contextul se ridică odată cu lansarea serverului HTTP și o singură dată. Acest lucru durează aproximativ 2 milisecunde și, în general, este ceva cu care poți trăi.

A doua problemă. Dacă s-a întâmplat brusc că biblioteca V8 a vrut să-și aloce memorie pentru ea însăși și nu a putut, „se blochează” în acel moment. În momentul în care lucram la acest motor de șablon cu JavaScript pe server, am reușit să contactez dezvoltatorul V8 - Vyacheslav Egorov. Apropo, el desfășoară spectacol, este o persoană celebră. Puteți găsi cu ușurință informații despre acesta. Aproape a confirmat aceste presupuneri. El susține (nu am verificat, să fim sinceri) că în actuala implementare V8, dacă nu reușește să aloce memorie, se aruncă o excepție care poate fi prinsă.

Dar el a recunoscut sincer că această excepție poate ajuta doar să repornească la timp și în întregime. Contextul este mort și nu se poate face nimic cu el. El nu răspunde la nimic și totul rămâne în memoria lui.

În ceea ce privește Nginx, cel mai probabil acest comportament este critic. Aici la Mail.ru, conform unuia dintre colegii noștri, în același RB, lucrul în condiții de memorie scăzută este considerat o situație normală. Și acolo unde lipsa memoriei este considerată o situație normală, cel mai probabil vor exista probleme. Dar dacă vorbim despre un proiect obișnuit, atunci dacă deodată începeți să rămâneți fără memorie pe mașina dvs., nu vă veți gândi la V8, ci la lucruri complet diferite.

Încă un moment neplăcut.

Acesta este un articol despre V8. Trunk V8 pare să fie într-o dezvoltare foarte activă. Vyacheslav însuși nu a putut reproduce această situație. Dar aici este reprodus cu bang. Sper că îl putem ajuta să rezolve.

La un moment dat am lansat V8 și am descoperit o scurgere de memorie. Am căutat o scurgere foarte mult timp, apoi am trecut de la trunk la versiunea 3.6.8, iar problema a dispărut. Portbagajul este problematic. Versiunea stabilă a Node.js este în prezent 06.14 și, de asemenea, trăiește pe 3.6. Dacă lucrați cu trunchiul, amintiți-vă: lucrați cu ceva care nu este foarte stabil. Totuși, comută la versiuni stabile, pentru care dezvoltatorii sunt responsabili.

Doar un link către API-ul V8, de care veți avea cu adevărat nevoie dacă intrați brusc în asta. Link către motorul nostru de șabloane. Nu pot spune că este OpenSource dintr-un motiv simplu. De fapt, OpenSource își asumă o anumită responsabilitate pentru ceea ce faci. Cel mai probabil ne vom lua asupra noastră, dar acum nu suntem pregătiți pentru asta. Așa că spun doar că ne dezvoltăm în mod deschis.

Tot ce am spus despre portbagajul V8 se poate întâmpla la noi. Momentan nu stabilizăm nimic. Acesta este un produs pe care îl dezvoltăm pentru noi înșine, dar formă deschisă. Ținând cont de faptul că dorim să-l publicăm pe OpenSource. Dacă există solicitări precum „cereri de tragere” (apropo, au fost deja de la unele persoane), atunci, desigur, salutăm un astfel de interes.

Atât am vrut să spun. Sunt gata să vă răspund la întrebări.

Intrebari si raspunsuri

Replica din sală: Mulțumesc pentru raport. Am o întrebare. Nu am înțeles cu adevărat povestea de fundal a motivului pentru care trebuia folosit un V8. Ai avut un site...

Andrei Sumin: Un pic mai mult de un site.

Replica din sală: Ai avut scenarii. Aceste scripturi de pe serverele back-end au început să încetinească. A fost așa sau nu?

Andrei Sumin: Nu deloc. Prin „site” te referi la proiectele „Mail.ru Pochta”?

Replica din sală: Da.

Andrei Sumin: Există mai multe probleme principale. În primul rând, avem șabloane duble. Șabloanele care sunt utilizate pe server nu pot fi utilizate pe client. Aceasta este o problemă. Trebuie să redăm lista de litere atât pe server, cât și pe client. Deci aveam nevoie de șabloane care funcționează peste tot. Este necesar ca același șablon să producă același rezultat atât pe client, cât și pe server. Aceasta este prima și cea mai importantă condiție prealabilă pentru trecerea la un V8.

A doua premisă. Am o mulțime de oameni în echipa mea care știu JavaScript. Dar nu există o singură persoană care să fie suficient de calificată pentru ca Mail.ru să cunoască, să zicem, C, Python sau ceva similar. Am oameni care sunt capabili să scrie JavaScript rapid, bun, fără scurgeri de memorie și așa mai departe. Dar nu există oameni care să poată scrie asta într-o altă limbă. Nu pentru că sunt practic incapabili, ci pentru că nu o fac în fiecare zi. În plus, pe lângă nevoia de șabloane uniforme pe client și server, avem nevoie și de specialiști care să poată face acest lucru. Acestea sunt două motive principale.

Replica din sală: Nu, uite aici. Dacă trebuie să redau o listă pe server, redau această listă acolo și atribui un identificator fiecărui element de acolo. Sau atribui o clasă unui grup de elemente. Ii scriu Script JavaScript, care face ceva acolo. Poate că există niște înlocuitori, nu știu... Motivația pentru utilizare nu este complet clară. De ce există șabloane duble?

Andrei Sumin: Avem o listă de scrisori pe „Mail”. Este compilat din unele date, trebuie desenat. Apoi venim la client, iar lista de scrisori este actualizată din când în când (deoarece persoana poate primi scrisori noi). În consecință, trebuie redat din nou. Acesta vine, firesc, către client sub formă de date. HTML-ul „Hăugărirea” necesită timp. Vine sub forma unor JSON.

În plus, avem diverse tipuri de optimizări. JSON a sosit, trebuie transformat în html. Acesta, din nou, este un șablon. Plus liste de scrisori. Pentru fiecare literă există suficiente informații, astfel încât atunci când utilizatorul face clic pe literă, ceva să i se afișeze utilizatorului - de exemplu, titlul scrisorii. Avem un subiect, un autor, putem afișa asta în așteptarea conținutului scrisorii. Acesta este un alt șablon.

Avem o mulțime de șabloane pe client. Tot felul de trucuri precum „Voi adăuga un identificator și voi scrie un cod simplu în JavaScript” chiar nu funcționează. Și când o persoană este pe pagina cu o scrisoare, poate apăsa acolo F5 și în acest moment trebuie să redăm această scrisoare pe server, pentru că este mai rapid în acest fel, destul de ciudat.

Scrisul este un subiect atât de complex. Există multă logică de șablon acolo. „De la”, „Către”, „Citește”, „Necitit”, „Important”, „Neimportant”. Sunt investiții, nu există investiții. Mult din toate.

Replica din sală: Clar. Mulțumesc.

Replica din sală: Am două întrebări. În primul rând: de ce ai ales V8-ul. Te-ai uitat la Partea JavaScript de la Mozilla (SpiderMonkey, TraceMonkey)?

Andrei Sumin: Sincer să fiu, ne-am uitat în direcția lui. Personal, am ales V8-ul, mai degrabă din motive politice. O companie mare face un produs pentru ea însăși. Motivul a fost acesta. Când am început să rulăm șabloanele rezultate pe client, în special, șablonul cu o listă de e-mailuri în Chrome „s-a extins” în 6 milisecunde, iar în Mozilla în 3 milisecunde. M-am gândit: poate s-a făcut o alegere greșită?

Ca rezultat, am obținut încă 1 milisecundă (pentru comparație: serverul nostru din Gzip petrece mult mai mult timp decât V8). Am decis să rămân cu V8 pentru moment. Poate că V8 va învinge în continuare SpiderMonkey. Deși în acest moment motorul nostru de șablon SpiderMonkey este mai rapid.

Motivele sunt încă politice. Ținând cont de faptul că în ceea ce privește viteza nu avem unde să mergem mai departe. Acum trebuie rezolvate alte probleme.

Replica din sală: A doua întrebare. Cum arată serverul din punct de vedere arhitectural? Este un proces care gestionează o grămadă de conexiuni, sau ce?

Andrei Sumin: Igor va răspunde – a scris-o. Este mai bine să-i dai dreptul de a răspunde.

Igor Sysoev: Da, este un proces care gestionează o grămadă de conexiuni.

Replica din sală: Este clar. Ai Epoll Linux?

Igor Sysoev: Da. Un proces.

Replica din sală: Toate conexiunile sunt procesate în același context?

Igor Sysoev: Da, un context.

Replica din sală: Este clar. Mulțumesc.

Replica din sală: Am o întrebare, în primul rând, despre redefinirea șabloanelor. Cum se rezolvă o astfel de problemă? Să presupunem că avem un bloc, vrem să afișăm acest bloc exact pe o pagină și să adăugăm altceva la el. Adăugați câteva informații suplimentare. Redefiniți apelarea blocului de bază. Ai spus că ai JavaScript. Cum se va exprima acest lucru? Va trebui să scrieți o inserare de asamblare în această sintaxă XML în JavaScript?

Andrei Sumin: Există mai multe opțiuni. Desigur, aceasta poate fi o inserție de asamblare sau puteți extinde singur limbajul șablonului. Dacă avem nevoie de el și nu pierdem în viteză, o vom face, poate în actualul motor de șabloane. Dacă aveți nevoie de acest lucru și aveți nevoie de aceleași viteze, atunci puteți pur și simplu să extindeți sintaxa curentă cu propria dvs. Sau trimite-ne un patch.

Replica din sală: Nu, desigur, înțeleg că astfel de facilități semantice nu sunt oferite „gratis” în ceea ce privește viteza. Întrebarea mea este diferită. Ce biblioteci de blocuri aveți atunci, pe care nu trebuie să le înlocuiți cu apelul metodei de bază?

Andrei Sumin: Acum nu prea înțeleg întrebarea.

Replica din sală: Aveți biblioteci care sunt utilizate apoi și în care există o modificare? Sau doar că totul este scris pe un singur proiect într-un singur strat și nu există suprascrieri și, prin urmare, nu este nevoie de o semantică bogată.

Andrei Sumin: Un proiect este scris exact așa. În prezent sunt în curs de redactare încă două sau trei proiecte. Acolo deja ne gândim la aceste lucruri. Aceste două sau trei proiecte sunt puțin mai simple când vine vorba de productivitate. Cel mai probabil, o vom rafina acolo.

Replica din sală: Mai am o intrebare. Mi-ai spus cât de grozav este că există specialiști grozavi în JavaScript. Pentru ei, toate acestea sunt clare și convenabile. De ce atunci folosiți sintaxa XML, de ce să nu puneți sintaxa în sintaxa JavaScript? Apoi specialistul va folosi un editor JavaScript „nativ”, de exemplu. Îi va fi mai ușor să citească codul banal, deoarece este același cod. Se pare că am unificat execuția acestor șabloane din punctul de vedere al motorului. Dar din punct de vedere al sintaxei, am creat, dimpotrivă, o a doua entitate.

Andrei Sumin: Entitatea a fost creată. Dar există mai multe motive. Aceasta este o consecință a mai multor decizii. În primul rând, am menționat că problema pe care neapărat trebuia să o rezolvăm era să învățăm cum să „gătim” JavaScript pe server. Pentru a o rezolva, nu am vrut să fiu distras prin a veni cu sintaxe, rezolvând probleme cu „scăpare” și așa mai departe.

Replica din sală: Dar sintaxa a fost inventată în JavaScript, iar problemele cu „scăparea” au fost rezolvate. Exact la fel ca cu XML.

Andrei Sumin: Nu, atunci când modelați în JavaScript, oricum veți inventa propriul limbaj.

Replica din sală: De ce? De ce inventez un limbaj în loc să scriu în JavaScript?

Andrei Sumin: Deoarece concatenarea șirurilor în JavaScript este o sarcină foarte ingrată.

Replica din sală: BINE. Nu înțeleg.

Andrei Sumin: Al doilea. Poate că atunci când JavaScript pe server devine obișnuit în multe proiecte (poate nu pentru întregul proiect), cel puțin atunci când este tratat ca o practică obișnuită, probabil va exista un alt motor de șabloane, altul decât fest. S-ar putea foarte bine să fie. De ce nu?

Dar aceasta este o sarcină de altă ordine. Nu era nevoie să o rezolvăm acum, pentru că erau probleme mai importante.

Al doilea. 99% dintre documentele noastre de ieșire sunt XML. Când aveți un construct de control XML și rezultatul este XML, este mult mai ușor pentru proiect, deoarece XML este înțeles de editori. Ei validează acest lucru, plus că există o grămadă de instrumente pentru lucrul cu XML. Momentan aceasta este decizia finală. Nu pot spune ce se va întâmpla într-un an.

Replica din sală: Bine, mulțumesc. Eu termin. Da, ceea ce spui este corect, dupa parerea mea. Problema principală este să aducem JavaScript pe server, iar apoi poate fi optimizat. Acesta este, în linii mari, un pas fundamental. Și apoi există îmbunătățiri minore fără principii care pot fi făcute în viitor. Vă mulțumesc și pentru această experiență.

Replica din sală: Am o întrebare în continuarea uneia dintre cele anterioare - despre un proces. Există într-adevăr un proces la care merg toate cererile? Sau acestea sunt mai multe procese pe porturi diferite, unde, prin amonte, să zicem, Nginx transmite diverse solicitări de la diferiți utilizatori?

Igor Sysoev: Nu. Nu există Nginx. Acolo - da, există un proces în care totul merge. De fapt, există mai multe furci pe o singură mașină. Toți atârnă de sâmburi. Clienții sunt cumva echilibrați acolo.

Replica din sală: Este clar. Mulțumesc.

Replica din sală: Alta intrebare. Acum câțiva ani am încercat să fac și JavaScript pe server. Depanarea a fost un iad complet. Ce instrumente de depanare folosiți pentru a profila toate acestea?

Andrei Sumin: Acum avem un bonus foarte mare - acesta este Node.js. Tot ceea ce rulăm se epuizează din cutie în Node.js. Există un instrument de depanare destul de bun acolo. În plus, dacă vorbim despre un motor de șabloane, putem oricând să trimitem șablonul nostru clientului. Există și mai multe instrumente de depanare.

În al treilea rând: așa cum am spus deja, pot exista unele suprapuneri specifice cu mediul. Puteți face ca mediul să „înainte” funcția. Avem o funcție care „redirecționează” jurnalul. De fapt, „redirecționează” „jurnal”, „var” și „eroare”, iar V8 poate „comunica” cu lumea exterioară. Mediul va scoate aceste date undeva. În plus, în API-ul V8 în sine există o mulțime de instrumente pentru a lucra cu V8 prin API-ul V8. Cel puțin atunci când „cade”, spune prin API că „cade”.

Replica din sală: Mulţumesc mult.

Replica din sală: Vă mulțumim pentru atenție.

Andrei Sumin: Multumesc tuturor.

  • Traducere

În 2009, platforma Node.js a făcut primii pași umili în lumea vastă a dezvoltării backend. Aceasta a fost prima încercare reușită de a utiliza JavaScript în aplicațiile server. Astăzi ar fi extrem de greu să găsești un dezvoltator web care să nu fi auzit de Node. Dar nu se poate spune că existența lui Node a fost fără nori. Această platformă a experimentat divizări ale comunității, a făcut obiectul războaielor pe forum și i-a determinat pe mulți la disperare.

S-ar putea să credeți că astfel de afirmații sună prea pompoase. Cu toate acestea, încercați să căutați pe Google și veți întâlni o sursă inepuizabilă de dezbateri fără sfârșit. Unele dintre argumentele anti-Nod pe care le puteți întâlni includ unele care, deși pun la îndoială ce s-a întâmplat cu axioma de a folosi cel mai bun instrument disponibil pentru a rezolva o problemă, subliniază că JS nu este nici pe departe soluția potrivită pentru server. Criticile despre JS, cum ar fi „Callback hell is real”, chemând să credem în realitatea callback hell, sună ca replici dintr-o poezie. Unii dintre criticii lui Node au spus-o mai clar: „Node este un cancer”.

Cred că este timpul să restabilim adevărata stare de lucruri, să punctăm toate i-urile cu privire la platforma Node.js și JavaScript ca limbaj de dezvoltare a serverului. Astăzi vom vorbi despre starea curentași dezvoltarea Node.js, cele mai de succes cazuri de utilizare pentru această platformă, limitările acesteia și tehnologiile create pe baza acesteia.

Starea actuală a Node.js ca platformă de server

Înainte de a vorbi despre cum arată platforma serverului Node astăzi, să ne amintim ce este.

Și anume, este un runtime JavaScript construit pe motorul V8 JS dezvoltat de Google și utilizat în Google Chrome. Node.js folosește un model I/O non-blocant, bazat pe evenimente, ceea ce face platforma simplă și eficientă.

La începutul acestui material, Node este prezentat ca un coșmar al programatorului. Cu toate acestea, nu este o coincidență că această platformă a devenit foarte populară. Aici nu ne vom baza pe declarații nefondate. Să ne uităm mai bine la fapte. Și anume, un studiu recent de la Stack Overflow arată că Node.js este în prezent cea mai populară tehnologie în rândul dezvoltatorilor.


În plus, JS este un limbaj a cărui popularitate a crescut mai rapid decât alte limbi în ultimii cinci ani, în timp ce C# și PHP au pierdut teren. Prevalența JavaScript, chiar dacă nu vorbim exclusiv despre Node, este în creștere.


Cum putem explica de ce JavaScript, ca limbaj pe partea de server, a fost adoptat atât de rapid și pe scară largă de comunitatea dezvoltatorilor? Mai simplu spus, Node a trecut printr-o fază în care a fost văzut ca un pic distractiv și a intrat într-o fază de stabilitate și maturitate. În jurul lui s-a format o comunitate puternică, a cărei dimensiune crește constant. Ecosistemul Node este, de asemenea, demn de menționat, ca, de exemplu, managerul de pachete Node, npm, în prezent reprezentat de cel mai mare registru de software de pe Internet.

Node.js nu numai că a revoluționat dezvoltarea pe server, dar a contribuit și la productivitate aplicații client, deoarece în dezvoltarea lui V8 au fost implicate forțe serioase. În plus, joacă un rol proeminent în extinderea întregului ecosistem JavaScript și îmbunătățirea cadrelor JS moderne, cum ar fi Angular, React sau Vue.

De-a lungul timpului, Node a reușit să răstoarne prejudecățile din primele zile. Aici sunt câțiva dintre ei.

Codul JavaScript pentru Node.js este notoriu dificil de depanat.

Pentru a depana aplicațiile JS de pe partea serverului, puteți utiliza aceleași tehnici pe care le utilizați pentru a depana codul de pe partea client, folosind node-inspector, care conține instrumente Chrome Developer Tools.

Nodul nu poate fi folosit pentru dezvoltare aplicații server clasa corporativă.

De asemenea, această afirmație nu este adevărată. Pe baza Node, puteți crea sisteme corporative. Singura dificultate este că nu are multe instrumente încorporate pentru a simplifica crearea unor astfel de sisteme. Cu toate acestea, jucători noti de pe piața IT folosesc Node ca platformă web corporativă. Printre acestea se numără și Netflix. PayPal, Yahoo!, Walmart.

JavaScript este un limbaj dinamic, așa că atunci când lucrați în el nu puteți folosi ceva de genul verificare statică tipuri în timpul compilării.

Asta este adevărat. Cu toate acestea, instrumente precum TypeScript și Flow au apărut în ecosistemul JS, care au ca scop lucrarea cu tipuri în JS, ceea ce face posibilă creșterea stabilității și predictibilitatea programelor și simplificarea depanării. În acest domeniu, puteți profita și de capacitățile Closure Compiler de la Google.

JavaScript nu a fost creat ca limbaj pentru dezvoltarea pe server.

Aici putem spune doar că JS ar putea deja să funcționeze pe servere în același timp în care Netscape a construit suport pentru această limbă în browserul său. Și asta era deja în 1995. JS este de obicei numit limbajul dezvoltării web pe partea clientului doar pentru că a preluat complet această zonă.

De fapt, lista poate continua.

Acum să vorbim despre cazurile de utilizare pentru Node.js și limitările sale pentru a înțelege mai bine locul acestei tehnologii în lumea modernă.

Scenarii de aplicare a nodului

Deci, de ce să luați în considerare Node.js ca un instrument de dezvoltare pe partea de server în stiva dvs. de tehnologie?

▍Avantaje și caracteristici generale

Permiteți-mi să rezumam cele mai importante lucruri pe scurt:
  • Este foarte probabil ca părțile client ale aplicațiilor dvs. web să fie scrise în JavaScript. În acest caz, versatilitatea codului din stiva de tehnologie utilizată este un avantaj important al utilizării JS pe server, ceea ce merită reținut.
  • Instrumente precum webpack ajută la reutilizarea codului atât pe client, cât și pe server, ceea ce duce la coerență la toate nivelurile sistemului.
  • Folosind JS pe client și server, puteți crea aplicații web care pot fi redate atât în ​​browser, cât și pe server. Mai mult, astfel de sisteme funcționează de obicei foarte clar și ușor de înțeles. Cred că acest lucru este pur și simplu uimitor.
  • Introducerea async/wait în Node a schimbat complet abordarea scrierii codului asincron. Acum acest cod seamănă cu codul sincron obișnuit și aspect, și prin comportament. Mecanismul async/wait a fost acceptat în Node începând cu versiunea 7.6. În special, este o soluție la problema notorie a iadului de apel invers.
Unii văd convergența bazei de cod client și server ca un dezavantaj al Node.js, spunând că forțează dezvoltatorul să folosească JavaScript. Cu toate acestea, acest lucru nu este chiar adevărat. Dacă este necesar, aplicațiile Node pot accesa biblioteci specializate de la terți.

Să presupunem că aveți nevoie de instrumente de codificare video. Pentru a vă echipa proiectul scris în JavaScript cu ele, nu trebuie să căutați niște biblioteci obscure și misterioase pentru Node. Puteți profita cu ușurință de instrumentele dovedite interacționând cu acestea din Node. Sau, de exemplu, dacă există o anumită bibliotecă Python care face ceea ce aveți nevoie calcule complexe, special pentru lucrul cu acesta, puteți lansa un microserviciu și puteți accesa funcțiile corespunzătoare ale acestei biblioteci prin API-ul REST.

Având în vedere toate cele de mai sus, putem evidenția următoarele cazuri de utilizare pentru Node.js, în care își dezvăluie pe deplin punctele forte.

▍Scenariul nr. 1. Aplicații în timp real

Aplicatii pentru colaborare(cum ar fi Trello și documente Google), chat-urile live, mesageria instantanee și jocurile online sunt exemple de aplicații în timp real care pot beneficia de arhitectura Node.js.

Timpul necesar acestor aplicații pentru a efectua anumite acțiuni poate fi caracterizat, din punctul de vedere al utilizatorului, prin cuvintele „imediat” și „acum”. Pentru ca astfel de aplicații să funcționeze corect, sistemul pe care se bazează trebuie să ofere foarte mult de mare viteză răspuns la acțiunile utilizatorului și latență scăzută. Node îndeplinește aceste cerințe.

Node facilitează gestionarea cererilor multiple de la clienți, arhitectura sa facilitează utilizare eficientă biblioteci, oferă o sincronizare foarte rapidă a datelor între client și server.

▍Scenariul nr. 2. Aplicații cu o singură pagină

O aplicație cu o singură pagină este o aplicație care este reprezentată de o singură pagină web care se încarcă în browser, al cărei conținut este actualizat dinamic pe măsură ce utilizatorul interacționează cu ea. Cea mai mare parte a încărcării la rularea unor astfel de aplicații cade pe partea client a sistemului, scrisă în JavaScript.

Chiar dacă aplicațiile cu o singură pagină reprezintă un pas semnificativ în evoluția dezvoltării web, ele au și probleme, precum randarea. În special, acest lucru poate avea un efect negativ asupra optimizării motoarelor de căutare pe pagină. O soluție populară la aceste probleme este redarea pe server folosind Node.js.

▍Scenariul nr. 3. Scalabilitate

Un server Node nu va fi niciodată mult mai puternic decât trebuie să fie. Frumusețea arhitecturii Node constă în minimalismul acesteia, în faptul că partea de server a aplicațiilor poate fi scalată în funcție de nevoile proiectului. Secretul aici constă în atitudinea corectă față de productivitate.

Chiar și numele subiectului conversației noastre, „nod”, se concentrează pe posibilitatea de a construi sisteme din multe noduri mici de calcul distribuite care pot face schimb de date între ele.

Modularitatea lui Node vă permite să creați aplicații mici fără a fi nevoie să mențineți o infrastructură uriașă, dintre care multe părți nu vor fi utilizate în niciun caz dat. La dezvoltarea aplicațiilor Node, programatorul alege exact ceea ce are nevoie și, dacă este necesar, extinde soluția.

Cu toate acestea, trebuie remarcat faptul că astfel de oportunități de scalare vin și cu anumite dificultăți. Și dacă nu ești atent, Node.js poate deveni... periculos.

Limitările Node.js

Sincer să fiu, Node îi permite dezvoltatorului să, așa cum se spune, „se împușcă în picior”. În lumea asta trebuie să plătești pentru tot, inclusiv oportunități ample privind configurarea sistemului și adaptarea acestuia la nevoile dvs. Dacă lucrați cu Node fără suficientă experiență sau lăsați în mod regulat lucrurile la voia întâmplării, este posibil să întâmpinați probleme grave, cum ar fi pierderea clienților.

Spre deosebire de abordările mai tradiționale care reglementează strict anumite caracteristici arhitecturale ale sistemelor, tu ești cel care creează structura care susține partea server a aplicației tale. Drept urmare, trebuie luate multe decizii, adică dezvoltatorul trebuie să știe exact ce face și ce se va întâmpla cu proiectul dacă acesta trebuie extins.

În cazul altor limbaje, cum ar fi Ruby și binecunoscutul cadru Ruby on Rails, de exemplu, există ideea că convențiile au prioritate față de configurația sistemului. Aceste cadre tradiționale conduc literalmente pe dezvoltator de mână, arătându-i modalitatea corectă și sigură de a rezolva problemele comune.

Node întoarce totul cu susul în jos, ca să spunem așa. Dezvoltatorului i se oferă mai multă libertate, dar calea spre realizarea planului poate fi plină de pericole dacă se iau decizii greșite în timpul lucrului. Aici ar fi potrivit să ne amintim de notoriul „iad de apel invers”, care se dovedește brusc a fi complet real.


Acest lucru nu înseamnă că nu puteți construi aplicații mari pe server pe Node, dar merită să țineți cont de cele de mai sus.

Chiar și creatorul lui Node.js, Ryan Dahl, și-a dat seama în cele din urmă de limitările sistemului înainte de a trece la alte proiecte. El a vorbit foarte fără echivoc despre această chestiune:

« Cred că Node nu este cel mai bun sistem pentru crearea de proiecte de server la scară largă. Aș folosi . Și sincer, de aceea părăsesc Node. Odată mi-am dat seama că, de fapt, acesta nu este cel mai bun sistem pentru dezvoltarea de servere».

Prejudecățile menționate anterior despre Node au fost adevărate până la un anumit punct în durata de viață nu atât de lungă a lui Node și, într-o oarecare măsură, nu sunt încă cuvinte goale. Nodul s-a maturizat și a crescut suficient, slăbiciunile sale, dacă este necesar și timpul disponibil, pot fi depășite. Iar instrumentele dezvoltate de comunitate vă permit să creați aproape orice bazat pe Node.js.

Instrumente populare pentru dezvoltarea JS pe partea de server

Nu cu mult timp în urmă, dacă cineva s-a gândit să construiască toate părțile sistemului său în JS, i-a venit imediat în minte gândul la stiva MEAN (MongoDB, Express, Angular și Node).

Acest set de instrumente nu și-a pierdut actualitatea astăzi, totuși, în prezent în ecosistemul JS există mult mai multe instrumente interesante atât pentru dezvoltarea clientului, cât și a serverului, așa că nu trebuie să vă limitați la MEAN.

Iată câteva cadre JS moderne, moderne, populare:

  • Express.js a fost și este în continuare cel mai popular framework Node.js. Este rapid, compact și nu impune dezvoltatorului decizii arhitecturale rigide. Baza dezvoltării sale rapide este simplitatea și claritatea. Poate că este mai aproape ideologic decât toate celelalte instrumente de ideile care stau la baza Node, în urma cărora este un sistem modular ușor.
  • Meteor, pe de altă parte, folosește JavaScript pur și Node.js într-un design destul de mare. Meteor în sine este un întreg ecosistem care poate fi potrivit pentru dezvoltarea de aplicații server mai complexe. Cu toate acestea, utilizarea Meteor poate deveni complicată dacă aveți nevoie de ceva care nu este încorporat în sistem.
  • Sails.js este un cadru MVC în timp real. A fost proiectat pentru a emula modelul MVC pe platforma Ruby on Rails, dar suportă în continuare cerințele aplicații web moderne. Totul funcționează datorită API-urilor care sunt conduse de date, în prezența unei arhitecturi scalabile, orientate spre servicii.

    Cred că cel mai important lucru pe care am vrut să-l fac este să arăt că între „da” și „nu” categoric care se găsesc în multe discuții despre Node și despre JS ca limbaj pe partea serverului, dacă există o zonă largă de „poate”.

    Și, vă place sau nu, interesul pentru Node este în continuă creștere.


    La sfârșitul acestui material, aș dori să spun că nu ar trebui să tratați niciun cadru ca pe o baghetă magică care va rezolva în mod magic toate problemele. Node.js este doar un instrument din universul colosal al dezvoltării web. În unele situații, rezolvă problemele care i-au fost atribuite excepțional de bine, în timp ce în altele, lucrul cu el se poate transforma într-un coșmar.

    Sarcinile fiecărui dezvoltator includ o selecție atentă de tehnologii potrivite pentru implementarea oricărui proiect nou. În același timp, este important să țineți cont de toate posibilitățile și să nu aruncați imediat alternativele disponibile.

    De exemplu, compania la care lucrez, Snipcart, folosește arhitectura .NET, despre care se pot spune o mulțime de lucruri neplăcute. De ce a fost aleasă? Da, pur și simplu pentru că la un moment dat s-a dovedit a fi cel mai bun instrument pentru rezolvarea sarcinii care ni s-a atribuit.

    Sper că povestea mea despre Node te va ajuta să iei decizia corectă atunci când alegi o platformă de server pentru următorul tău proiect.

    Etichete: Adăugați etichete

Întrebarea „De ce?” - cel mai important lucru atunci când luați orice decizie. În cazul nostru au fost mai multe motive.

În primul rând, oamenii. Motorul actual de șablon a fost procesat de C. Toate întrebările legate de modificările sale nu au fost rezolvate rapid. Și cel mai important lucru este că motorul de șablon a fost scris de unii oameni și folosit de oameni complet diferiți.

În general, acest lucru este obișnuit și, după părerea mea, nu foarte bun antrenament instrumente de scriere pentru designeri de layout. Este clar că au nevoie de instrumente, dar aceste instrumente sunt implementate de oameni care au doar o idee vagă despre sarcinile zilnice ale designerilor de layout. Mai degrabă, dimpotrivă, deciziile sunt adesea luate în sensul „lasă-i să scrie condiții și cicluri, dar nu vor avea nevoie de nimic altceva pentru aspect”. Poate că aceasta este vina designerilor înșiși și a calificărilor lor.

Dar Mail.Ru Group are o echipă întreagă de oameni cu înaltă calificare care cunosc JS, sunt capabili să scrie un instrument pe cont propriu și, cel mai important, îl vor folosi.

În al doilea rând, sarcinile. Să luăm proiectul [email protected]. Nu putem refuza șablonarea pe server - avem nevoie încărcare rapidă la prima intrare. Nu putem refuza șablonarea pe client - oamenii trebuie să vadă o viteză mare de răspuns la acțiunile lor, ceea ce înseamnă că sunt necesare AJAX și șablonarea pe client.

Problema este evidentă: două seturi de șabloane complet diferite pe server și pe client. Și cel mai ofensator este că rezolvă aceeași problemă. Dublarea logicii pur și simplu ne-a epuizat.

V8 este un interpret JavaScript, ceea ce înseamnă că putem obține un șablon care funcționează atât pe server, cât și pe client.

În al treilea rând, viteza. După ce am citit multe articole care lăudau viteza v8, am decis că trebuie să le verificăm validitatea. Dar mai întâi trebuia să înțelegem cum doream să arate noul motor de șablon.

De ce ai nevoie

Voi spune imediat că suntem foarte limitati în ceea ce privește timpul serverului pentru transformare, așa că implementarea a ceva este foarte funcţionalitate nu a avut. Cu toate acestea, lăsarea vechii funcționalități cu singura diferență fiind adăugarea unui strat de la v8 este o idee ciudată.

Il folosesc mult de mult timp Transformări XSLT(nu este cea mai rapidă opțiune de transformare), deși dacă este folosită corect arată numere bune (vorbesc despre libxslt). Dar XSLT are un instrument de șabloane foarte puternic - suprascrierea șablonului. Am decis să implementăm ceva asemănător, dar mult mai simplu.

/head.xml... <fest:get name=”title”/> Mail.ru/mail.xml... Mail.ru mail

Ar fi ciudat să folosiți v8 și să nu oferiți acces la JavaScript în șabloane.

var text = „mail.ru” text

Și o mulțime de alte lucruri mici, pe lângă condițiile și ciclurile standard.

Am luat XML ca sintaxă pentru motorul de șabloane.

Suport pentru funcționalitatea de bază în IDE. Sută la sută dintre IDE-urile populare știu ce este XML. Obțineți gratuit silabe, evidențiere și completare automată de bază.

Validare la nivel IDE. HTML valid este obținut prin șabloane valide. Din nou, toate IDE-urile pot valida xml ca atare.

Modularitate ieșită din cutie (spații de nume). Caracteristici de bază Motorul de șablon va dori foarte repede să fie extins. De exemplu, adăugați o etichetă care vă permite să creați proiecte în mai multe limbi. Sistemul Name Spaces face acest lucru ușor.

Gamă largă de instrumente gata făcute. De-a lungul anilor, s-au acumulat multe instrumente pentru procesarea XML, de exemplu, biblioteci pentru procesarea XML folosind XSL sau o întreagă clasă de analizoare SAX, scheme XSD și DTD pentru validare etc.

Coincidența sintaxei structurilor de procesare și a structurilor rezultate. Cu alte cuvinte, crearea XML folosind XML este convenabilă, șabloanele de festival sunt ușor de citit. În plus, toate problemele de protecție a datelor au fost rezolvate.

Implementarea

Cowboyism. Eu însumi am aflat recent că există un astfel de termen.

Înainte de asta, eram sigur că cel mai mult mod de încredere finalizarea sarcinii - programarea perechilor și teste. Testele, ca întotdeauna, s-au justificat, dar au existat alternative la programarea perechilor.

Diferența dintre această sarcină și una tipică: șablonul și HTML-ul rezultat pe care acest șablon ar trebui să îl producă erau cunoscute. Kostya (dezvoltator de mail Frontend) și cu mine am început să scriem propriile noastre implementări. O dată pe săptămână am comparat măsurătorile ratei de transformare.

Am luat două abordări diferite: el a compilat șablonul într-o funcție, iar eu am compilat într-o structură. Un exemplu de cea mai simplă structură:

... ", 04 (acțiune:"valoare"), 05 "json.value" 06 ]

A doua linie marchează începutul modelului. Al treilea ar trebui pur și simplu dat browserului. Al patrulea spune că al cincilea ar trebui să fie executat ca JavaScript și rezultatul execuției ar trebui să fie dat browserului.

01 [ 02 (acțiune:"șablon"), 03 " ....”, 04 (acțiune: „dacă”), 05 „json.value”, 06 „adevărat”, 07 „fals” 08 ]

Opțiunea este puțin mai complicată. A patra linie înseamnă că a cincea trebuie executată și dacă rezultatul este adevărat sau fals, atunci dați a șasea sau, respectiv, a șaptea linie.

Opțiunea cu funcția nu trebuie să fie explicată în mod special.

01 șablon de funcție (json)( 02 var html = ""; 03 html += " ..."; 04 html += json.value; 05 return html; 07 )

Privind în viitor, voi spune că versiunea lui s-a dovedit a fi mai rapidă. De ceva vreme am mers aproape la nivel, dar varianta de structura a lovit tavan mult mai devreme.

Pentru a înțelege ce a oferit această abordare: prima mea implementare a finalizat sarcina în 200 ms. Când am stors tot ce am putut și apoi am combinat cele mai bune dintre cele două programe ale noastre, am primit 3 ms.

Dacă descriem pe scurt implementarea curentă, traducem ciclurile în cicluri, declarații condiționaleîn declarații condiționale etc.

Fest:foreach for(i = 0; i< l; i++) {} fest:if if(value) {} fest:choose if(value) {} else {}

Fără îngustarea contextului. Da, aceasta este o limitare, dar nu există nicio taxă generală pentru limitarea contextului, iar cel mai important lucru este că, de îndată ce restrângeți contextul, apare imediat sarcina de a obține ceva din contextul global sau dintr-un context la un nivel superior. nivel.

Este important ca șabloanele să fie traduse într-o funcție JS care funcționează în modul strict. Acest lucru îi împiedică pe programatori să scrie cod care va duce la pierderi de memorie.

Oriunde ai nevoie munca logica cu date, JavaScript este disponibil.

_javascript_

Toate modelele care implică Execuție JavaScript, se transformă în try catch.

Toate constructele care așteaptă rezultate în HTML după executarea JavaScript trec evadarea HTML în mod implicit.

json.name
încercați ( html += __escape(json.name) ) catch(e) ()

De la bun început, dezvoltarea motorului de șablon se realizează în formă deschisă.
https://github.com/mailru/fest

Opțiuni de integrare

Pe de o parte, v8 este doar o bibliotecă care permite interpretarea JavaScript. În sine, pare inutil - fără acces la sistem. Dar, pe de altă parte, poate fi ușor înșurubat în alte limbi.

Având zero experiență de programare în C și Perl, am realizat cazuri de testare în ambele limbi. În plus, în acest moment avem o conexiune cu Python.

Și, bineînțeles, NodeJS pentru prototipuri și browsere - medii în care șabloanele JavaScript funcționează imediat.

Condiții aproape de luptă

După ce am primit 3 ms, m-am dus la programatorii de pe server. Când au fost întrebați cât timp am pentru o solicitare care returnează o listă de e-mailuri de utilizator, ei au spus: nu mai mult de 4 ms. Aveam deja 3ms pentru transformare, trebuia sa o incerc.

Lista noastră de scrisori este furnizată de propriul nostru server http, scris în C. Recepția datelor sunt operațiuni care nu concurează pentru procesor, deci nu au fost măsurate. Ne-am hotărât pe pregătirea datelor pentru transformare și pe transformarea în sine.

Din motive istorice noastre server http stochează datele într-un hash plat.

Msg_length = 5 msg_1_title = „litera” msg_1_Unread = 1

Din moment ce vorbim despre JavaScript, primul lucru care ne vine în minte este JSON

Msg = [ (titlu: „scrisoare”, Necitit: adevărat)]

Am luat un șir cu un hash plat, l-am plasat în memorie și am început să obținem rezultatul când, la transformarea șablonului în v8, JavaScript a funcționat cu JSON.

Am trecut prin multe opțiuni. Treceți un obiect, treceți un șir și analizați-l în JavaScript, treceți un șir și treceți-l prin JSON.parse.

Destul de ciudat, cel mai rapid lucru s-a dovedit a fi convertirea hash-ului plat într-un șir care se potrivește cu JSON și, în v8, dați șirul

„șablon([ (titlu: \„scrisoare\”, Necitit: adevărat) ])”

Dar, în ciuda tuturor, am lovit 6ms cu o transformare de 2ms. Toată lumea era gata să renunțe. Am decis în continuare să iau datele originale, un șir hash plat și, folosind același șablon compilat, să obțin HTML-ul dorit în NodeJS.

Am 4 ms. Când am venit la inginerii noștri cu această cifră, să fiu sincer, mă așteptam la expresia „Cool, dar nu avem resursele pentru a scrie NodeJS”, dar am auzit „Dacă NodeJS poate face asta în 4 ms, atunci noi o pot face si tu!”

În acel moment mi-am dat seama că vom aduce asta în producție. E un al doilea vânt!

Soluția s-a dovedit a fi simplă. Deoarece pierdem 67% din timpul nostru cu pregătirea datelor și, în principiu, avem deja datele, trebuie să renunțăm la pregătirea datelor.

Am redirecționat funcția __get('key') către v8. Astfel, din v8 am preluat date direct din hash-ul serverului nostru http. Nu există conversie de date în formatul necesar. Nu există nicio conversie a acestui șir într-un obiect în interiorul v8. Am ajuns la 3ms și aveam o marjă de 1ms.

Aproape producție

Deci, totul arată grozav, dar încă nu ne-am apropiat de producție. Mă mâncărime mâinile să încerc.

Luăm un server separat, instalăm pe el o versiune a serverului http care funcționează cu v8 și duplicăm cererile reale către acesta. Lăsăm un nucleu Xeon de 2,2 GHz timp de 30 de ore.

10.000.000+ de accesări 1,6 ms timp mediu de transformare 992.422 10% între 2 și 5ms 208.464 2% între 5 și 10ms 39.649 0,4% mai mult de 10ms

Doar 12% au fost mai mari de 2 ms. v8 se comportă stabil din memorie.

Productie

Am venit cu cele mai recente numere la directorul tehnic adjunct, spunându-i că v8 este gata de producție, trebuie să facem un mic proiect separat, care, dacă este ceva, poate fi uitat în caz de eșec. Răspunsul pe care l-am primit a fost „cifrele sunt bune, un proiect separat al cărui eșec nu este groaznic - este corect, dar chiar doriți să lansați v8? Începeți cu pagina principală a Mail.Ru.” Întrebarea este pusă corect - fie ne facem treaba, fie ne distrăm pe margine.

Așezarea paginii principale la festival a durat trei zile. Am oprit un server de la echilibrator, am încărcat acolo versiunea v8 și am duplicat solicitările. Toate calculele vor avea loc în contextul unui demon/nucleu.

Aflați întotdeauna în detaliu ce arată graficele dvs. Punem jumătate din sarcină pe serverul de testare. Consumul procesorului a fost de trei ori mai mare decât de obicei. Părea un eșec, o pierdere de resurse de șase ori în comparație cu actualul motor de șablon.

Au început să privească. Aici am sa va povestesc putin despre arhitectura principala. Acesta colectează informații din diferite proiecte. Este asamblat intern, îl numim RB. Din cei 165 kb care sunt generați pentru fluxul principal, 100 kb sunt colectați de RB. Și se întâmplă următoarele: RB trimite bucăți de HTML prin serverul http către v8, v8 le concatenează cu propriile șiruri de caractere, iar rezultatul returnează totul înapoi la serverul http.

Există o dublă transmitere a datelor. Am făcut optimizarea. Acum v8, în loc să construiască un șir mare, inclusiv date de la RB, trimite datele direct către serverul http.

Push_string('foo'); __push_rb(id); __push_string('bara');

Ca un plus, nu există concatenare de șiruri pe v8, nicio redirecționare dublă a RB de la server la v8 și înapoi și, cel mai important, orice transmitere de date este o conversie de la utf-8 la utf-16 și înapoi. V8 stochează totul în utf-16.

A fost profit, resursele au fost consumate de două ori mai mult decât de obicei, nu trei. Acestea. am pierdut încă de patru ori, deși părea că am stors fiecare picătură.

Acum vine partea educațională. Pentru distracție, am luat încărcătura pe care am testat-o ​​și am înmulțit-o cu două, cu numărul de demoni de pe mașină și cu numărul de mașini. A primit 440.000.000 de accesări. În același timp, avem 110.000.000 de accesări pe zi. S-au strecurat îndoieli vagi.

Hai să vedem logiile. S-a dovedit că pentru fiecare solicitare cu încărcare, am primit trei solicitări cu rapoarte în jurnalele pentru statistici! Sarcina reală pe un server http este de patru ori mai mică decât cea pe care testăm!

A doua zi dimineață am lansat versiunea v8 a paginii principale.

Date pentru azi:
Dimensiunea HTML-ului de ieșire pe care v8 îl generează este de 65 kb.
Timpul v8 funcționează pe cerere 1 ms.
În medie, v8 necesită 40 MB per context.

Câteva precizări

Toți cei care se gândesc la v8 au dat peste un articol de Igor Sysoev