Structurarea proiectului

Când am început să construiesc aplicații Node & Express, nu știam cât de important este să vă structurați aplicația. Express nu vine cu reguli sau instrucțiuni stricte pentru menținerea structurii proiectului.

Sunteți liber să utilizați orice structură doriți. Când baza de cod crește, ajungeți să aveți mult timp route manipulatori. Acest lucru face codul dvs. greu de înțeles și conține erori potențiale.

Dacă lucrați pentru o pornire, de cele mai multe ori nu veți avea timp să vă refractați proiectul sau să îl modulați. Puteți termina cu o buclă nesfârșită de remediere și corecție a erorilor.

De-a lungul timpului, în timp ce lucram atât cu echipe mici, cât și cu echipe mari, mi-am dat seama ce tip de structură poate crește cu proiectul tău și totuși să fie ușor de întreținut.

Model View Controller

MVC modelul ajută la dezvoltarea rapidă și paralelă. De exemplu, un dezvoltator poate lucra la vizualizare, în timp ce altul poate lucra la crearea logicii de afaceri în controler.

Să aruncăm o privire la un exemplu de aplicație CRUD simplă pentru utilizator.

project/
  controllers/
    users.js
  util/
    plugin.js
  middlewares/
    auth.js
  models/
    user.js
  routes/
    user.js
    router.js
  public/
    js/
    css/
    img/
  views/
    users/
      index.jade
  tests/
    users/
      create-user-test.js 
      update-user-test.js
      get-user-test.js
  .gitignore
  app.js
  package.json
  • controlere: Definiți gestionarii rutelor aplicației și logica de afaceri
  • util: Scrie aici funcții de utilitate / ajutor care pot fi utilizate de orice controler. De exemplu, puteți scrie o funcție ca mergeTwoArrays(arr1, arr2).
  • mijlocii: Puteți scrie middlewares pentru a interpreta toate cererile primite înainte de a trece la handler-ul rutei. De exemplu,
    router.post('/login', auth, controller.login) Unde auth este o funcție middleware definită în middlewares/auth.js.
  • modele: de asemenea, un fel de middleware între controlerul dvs. și baza de date. Puteți defini o schemă și puteți face unele validări înainte de a scrie în baza de date. De exemplu, puteți utiliza un tip ORM Mangustă care vine cu caracteristici și metode excelente de utilizat în schemă
  • trasee: Definiți rutele aplicației, cu metode HTTP. De exemplu, puteți defini tot ce ține de utilizator.
router.post('/users/create', controller.create)
router.put('/users/:userId', controller.update)
router.get('/users', controller.getAll)
  • public: Stocați imagini statice în/img, fișiere JavaScript personalizate și CSS /css
  • vizualizări: Conține șabloane care trebuie redate de server.
  • teste: Aici puteți scrie toate testele unitare sau testele de acceptare pentru serverul API.
  • app.js: Acționează ca fișierul principal al proiectului în care inițializați aplicația și alte elemente ale proiectului.
  • package.json: Se ocupă de dependențe, de scripturile de executat cu npm comandă și versiunea proiectului dvs.

Excepții și gestionarea erorilor

Acesta este unul dintre cele mai importante aspecte la care trebuie să vă gândiți atunci când creați orice proiect cu orice limbă. Să vedem cum să gestionăm erorile și excepțiile cu grație într-o aplicație Express.

Folosind promisiuni

Unul dintre avantajele utilizării promisiunilor față de apelurile de apel este că pot gestiona excepții / erori implicite sau explicite în blocuri de cod asincrone, precum și pentru codul sincron definit în .then(), o promisiune de apel invers

Doar adauga .catch(next) la sfârșitul lanțului de promisiuni. De exemplu:

router.post('/create', (req, res, next) => {

   User.create(req.body)    // function to store user data in db
   .then(result => {
   
     // do something with result
    
     return result 
   })
   .then(user => res.json(user))
   .catch(next)
})

Folosind try-catch

Try-catch este un mod tradițional de a prinde excepții în codul asincron.

Să aruncăm o privire la un exemplu cu posibilitatea de a obține o excepție:

router.get('/search', (req, res) => {
 
  setImmediate(() => {
    const jsonStr = req.query.params
    try {
      const jsonObj = JSON.parse(jsonStr)
      
      res.send('Success')
    } catch (e) {
      res.status(400).send('Invalid JSON string')
    }
  })
})

Evitați utilizarea codului sincron

Cod sincron, cunoscut și sub numele de cod de blocare, deoarece blochează execuția până când acestea sunt executate.

Deci, evitați să utilizați funcții sau metode sincrone care ar putea dura milisecunde sau microsecunde. Pentru un site web cu trafic ridicat, acesta se va compune și poate duce la o latență ridicată sau la un timp de răspuns la solicitările API.

Nu le folosiți în producție mai ales 🙂

Multe module Node.js vin împreună cu ambele .sync și .async metode, deci utilizați asincronizarea în producție.

Dar, dacă totuși doriți să utilizați o utilizare API sincronă --trace-sync-io steagul liniei de comandă. Acesta va imprima un avertisment și o urmă de stivă ori de câte ori aplicația dvs. folosește un API sincron.

Pentru mai multe informații despre fundamentele gestionării erorilor, consultați:

Ce ar trebui nu face este de a asculta pentru uncaughtException eveniment, emis atunci când o excepție bulă tot drumul înapoi la bucla evenimentului. Folosirea acestuia este în general nu este preferat.

Logarea corectă

Înregistrarea este esențială pentru depanare și activitatea aplicației. Este utilizat în principal în scopuri de dezvoltare. Folosim console.log și console.error dar acestea sunt funcții sincrone.

În scopuri de depanare

Puteți utiliza un modul ca depanare. Acest modul vă permite să utilizați variabila de mediu DEBUG pentru a controla la ce mesaje de depanare sunt trimise console.err(), dacă există.

Pentru activitate în aplicație

O modalitate este să le scrieți în baza de date.

Verifică Cum am folosit plugin-uri mongoose pentru a efectua auditul aplicației mele .

O altă modalitate este de a scrie într-un fișier SAU utilizați o bibliotecă de jurnalizare ca Winston sau Bunyan. Pentru o comparație detaliată a acestor două biblioteci, consultați postarea pe blogul StrongLoop Compararea înregistrării Winston și Bunyan Node.js.

necesită („./../../../../../../”) mizerie

Există diferite soluții pentru această problemă.

Dacă găsiți că orice modul devine popular și dacă are independență logică față de aplicație, îl puteți converti în modul privat npm și îl puteți folosi ca orice alt modul din package.json.

SAU

const path  = require('path');
const HOMEDIR  = path.join(__dirname,'..','..');

Unde __dirname este variabila încorporată care numește directorul care conține fișierul curent și .. ,..este numărul necesar de pași în arborele directorului pentru a ajunge la rădăcina proiectului.

De acolo este pur și simplu:

const foo = require(path.join(HOMEDIR,'lib','foo'));
const bar = require(path.join(HOMEDIR,'lib','foo','bar'));

pentru a încărca un fișier arbitrar în cadrul proiectului.

Spune-mi în comentariul de mai jos dacă ai idei mai bune 🙂

Setați NODE_ENV la „producție”

NODE_ENV variabila de mediu specifică mediul în care rulează o aplicație (de obicei, dezvoltare sau producție). Unul dintre cele mai simple lucruri pe care le puteți face pentru a îmbunătăți performanța este să setați NODE_ENVla „producție”.

Setare NODE_ENV la “producție”Face Express:

  • Șabloane de vizualizare cache.
  • Cacheează fișierele CSS generate din extensiile CSS.
  • Generați mesaje de eroare mai puțin detaliate.

Testele indică că doar acest lucru poate îmbunătăți performanța aplicației cu un factor de trei!

Folosind Process Manager

Pentru producție, nu ar trebui să utilizați pur și simplu node app.j – dacă aplicația dvs. se blochează, va fi offline până când o reporniți.

Cei mai populari manageri de proces pentru Node sunt:

Eu personal folosesc PM2.

Pentru o comparație caracteristică cu caracteristică a celor trei manageri de proces, consultați http://strong-pm.io/compare/. Pentru o introducere mai detaliată a tuturor celor trei, a se vedea Managerii de proces pentru aplicațiile Express.

Rulați aplicația într-un cluster

Într-un sistem multi-core, puteți crește performanța unei aplicații Node de multe ori prin lansarea unui cluster de procese.

Un cluster rulează mai multe instanțe ale aplicației, în mod ideal o instanță pe fiecare nucleu CPU. Aceasta distribuie sarcina și sarcinile între instanțe.

Folosind modulul cluster Node

Clusterizarea este posibilă cu Node’s modulul cluster. Aceasta permite unui proces master să genereze procesele lucrătorilor. Distribuie conexiunile primite între lucrători.

Cu toate acestea, mai degrabă decât să utilizați acest modul direct, este mult mai bine să utilizați unul dintre multele instrumente care o fac automat pentru dvs. De exemplu nod-pm sau serviciu cluster.

Folosind PM2

Pentru pm2 puteți utiliza clusterul direct printr-o comandă. De exemplu,

# Start 4 worker processes
pm2 start app.js -i 4

# Auto-detect number of available CPUs and start that many worker processes
pm2 start app.js -i max 

Dacă întâmpinați probleme, nu ezitați Intră atingere sau comentează mai jos.
Aș fi bucuros să vă ajut 🙂

Nu ezitați să bateți din palme dacă ați considerat că este o lectură utilă!

Referințe: https://expressjs.com/en/advanced/best-practice-performance.html

Publicat inițial la 101node.io pe 30 septembrie 2018.