Node.js för PHP-utvecklare: 5 praktiska aspekter som du måste känna till med kodexempel Node.js för PHP-utvecklare:

Medans Node.js blir allt populärare, minskar PHP:s popularitet. Med det sammanhanget kommer det här inlägget att utveckla 5 praktiska aspekter som måste vara kända när det gäller att använda Node.js för PHP-utvecklare. Detta kommer att vara saker som ingen pratar eller skriver om, dags att sätta igång.

  1. Node.js för PHP-utvecklare (inte Node.js vs PHP)
  2. Node.js för PHP-utvecklare den praktiska sidan
    1. Node.js-kodutförande är asynkront och icke-sekventiellt
      1. Node.js lovar möjligheter
    2. Node.js-processen är långvarig, till skillnad från PHP
      1. Exempel på memotisering
      2. Exempel på anslutningspool med MySQL
    3. Debuggning är enklare i Node.js än i PHP
    4. Grova versionsuppgraderingar i Node.js är smidigare än i PHP
    5. Dockerisering av en Node.js applikation är en barnlek jämfört med PHP
  3. Slutsats

Node.js för PHP-utvecklare (inte Node.js vs PHP) #

Detta stycke är en lista över saker som du som PHP-utvecklare måste känna till och lära dig för att använda Node.js effektivt. Tvärtom är det här inlägget inte en Node.js vs PHP-skrivelse där PHP basheras. Jag har använt båda språken. Jag började skriva mer Node.js under 2016. När jag började stötte jag på vissa svårigheter eftersom jag var van vid PHP på jobbet i mer än 7 år innan dess. Det släpptes en bok mot slutet av 2012 som täcker Node.js för PHP-utvecklare.

Detta blogginlägg kommer inte att tala om vad PHP eller Node.js är, du kan läsa om det i andra inlägg. Jag kommer inte heller att prata mycket om Non-Blocking I/O eller event loop. Ändå kommer en del av det att strykas över när vi diskuterar de praktiska aspekterna av att skriva bra Node.js-kod.

Node.js för PHP-utvecklare den praktiska sidan #

PHP har funnits sedan 1995 och enligt uppgift används det fortfarande av 79,% av de webbplatser som övervakas av W3tech (jag kan inte riktigt säga om det är hela internet). Så chansen är mycket stor att du har använt PHP eller använt något som är skrivet i PHP. Till exempel med en växande trend:

WordPress används av 63,7 % av alla webbplatser vars innehållshanteringssystem vi känner till. Detta är 39,0 % av alla webbplatser som övervakas av W3Tech.

Å andra sidan släpptes Node.js 2009. Stora teknikföretag som Linked In och Paypal började använda det 2011-2013 av olika skäl som mikrotjänster. Enligt Stack Overflow utvecklarundersökning från 2020:

För andra året i rad tar Node.js förstaplatsen, eftersom den används av hälften av de svarande.

Det är ingen hemlighet att Node.js har blivit väldigt populärt under de senaste fem åren.

Så som PHP-utvecklare är det här fem praktiska saker som du måste veta för att bli en bra Node.js-programvaruingenjör. Node.js för PHP-utvecklare är liknande i vissa avseenden men också annorlunda i vissa andra aspekter några beskrivs nedan:

Node.js kodkörning är asynkron och icke-sekventiell #

Detta är ett beteende som lurar många PHP-utvecklare. I PHP körs koden i sekvens, först rad 1 sedan 2 och så vidare. I Javascript och i synnerhet i Node.js är detta kanske inte fallet. Du kan potentiellt sätta saker i bakgrunden med god användning av löften och callbacks.

Nedan följer ett modifierat kodexempel med en förklaring som är hämtad från min open source currency-api repo:

async function getExternal(fromCurrency, toCurrency, onDate) {
const rate = await getRate(fromCurrency, toCurrency, onDate);
db.query(
`INSERT INTO exchange_rates (from_currency, to_currency, rate, on_date) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE rate = ?`,

).then(result => {
if (result.affectedRows === 0) {
console.error(`Exchange rate of ${rate} for ${fromCurrency} to ${toCurrency} on ${onDate} could not be saved`);
}
}).catch(err => {
console.log(`Error while writing to db: `, err);
}); //this is done async for the API to respond faster
console.log(`Fetched exchange rate of ${rate} for ${fromCurrency} to ${toCurrency} of ${onDate} from the API`);
return { fromCurrency, toCurrency, onDate, rate };
}

Om du tittar närmare så har den där oskyldiga db.query som ser oskyldig ut på rad 3, skjutits i bakgrunden. Så det kommer att utföras som nedan:

  1. Get rate
  2. Run insert query in the background
  3. Medans insatsen körs funktionen är redan returnerat rate
  4. Om det finns ett problem i insatsen query det loggas i catch

Det finns ingen out of the box sätt att göra något sådant här i PHP. Det här är det första som gör PHP-utvecklare förbryllade. Det gör det svårare att förstå Node.js för PHP-utvecklare. Detta asynkrona beteende för kodutförande gör det också svårare att hitta rätt stacktrace vid fel i Node.js.

För att vara ärlig kan du i 2020 enkelt använda async await. Även om det är syntaktiskt socker på Promises gör det asynkron programmering mycket enklare. När jag började i Node 4/6-eran runt 2016 med callbacks och Promises var det ett helt annat spel. Var ändå försiktig när du inte ska använda async-await (som ovan) och bara gå med promises, then och catch. Bli inte trasslad in i löfteshelvetet i processen dock. Promise hell är som nästa iteration av callback hell.

Pro tips: Om du vill veta vilka ES6-funktioner du kan använda med vilken version av Node.js kan du kolla in det på node.green.

Ett annat proffstips:

Vissa Node.js versioner är LTS, udda versioner är det inte. Så använd Node 14 eller 16 inte 13 eller 15 i produktionen.

Om vi går lite djupare in på icke-sekventiell exekvering spelar löften och den kraft de har en viktig roll här. Möjligheten att göra samtidiga saker är fantastisk i Node.js och javascript i allmänhet.

Node.js promises möjligheter #

Då löften är asynkrona kan du köra dem samtidigt. Det finns olika sätt att göra det på. Du kan tävla mot 3 promises och få resultaten från den snabbaste. Du kan till och med göra promise.all där om ett löfte avvisas stoppar det hela operationen. Läs gärna mer om Promise.race, promise.all och promise.any i den här utmärkta jämförelsen.

Med detta i åtanke kan du prova andra NPM-bibliotek för att begränsa löfteskonkurrens eller till och med filtrera genom löften samtidigt. Du kan göra en del av det med ReactPHP. Men det ingår inte i det ursprungliga PHP, inte ens i PHP 8. Det här är något nytt att sätta sig in i Node.js för PHP-utvecklare.

Låt oss gå vidare till nästa punkt, processen behöver inte dö i Node.js som i PHP.

Node.js-processen är långvarig, till skillnad från PHP #

PPHP är tänkt att dö, inte i den bemärkelsen att den inte kommer att användas. I den meningen att alla PHP-processer måste dö. PHP är egentligen inte konstruerat för långvariga uppgifter/processer. I PHP när en ny HTTP-förfrågan kommer in startar bearbetningen, efter att svaret skickats tillbaka dödas processen. Det är så PHP fungerar. Det skapar behovet av FPM och andra servrar. Man kan hävda att PHP var serverlös till sin utformning för över 20 år sedan. Jag lämnar det upp till dig.

På andra sidan är Node.js en långvarig process. Detta gör det möjligt att dela information mellan förfrågningar eftersom samma server/process hanterar flera förfrågningar. Med en långkörande process kan du enkelt utnyttja saker som memoization på minnet och connection pooling för en databas. Det öppnar andra möjligheter som att till exempel räkna antalet samtidiga förfrågningar på den processen.

Memoization exempel #

Om du inte känner till Memoization.

Memoization är en funktion av högre ordning som cacher en annan funktion. Den kan förvandla vissa långsamma funktioner till snabba funktioner. Den sparar resultatet av ett funktionsanrop efter första gången i cacheminnet, så om du anropar funktionen igen med samma argument kommer den att hitta den i cacheminnet.

Den kan användas i Node.js men inte i PHP nativt. Vissa lösningar är möjliga i PHP som att spara funktionens returvärde i Redis.

Nedan följer ett kodprov på memoisering på en expressrutt med p-memoize:

const ONE_MINUTE_IN_MS = 60000;
const options = {
maxAge: ONE_MINUTE_IN_MS,
cacheKey: (arguments_) => arguments_.join(','),
};
app.get('/api/products', async (req, res, next) => {
try {
const memGetProducts = pMemoize(products.getMultiple, options);
res.json(await memGetProducts(req.query.page || 1, req.query.search));
} catch (err) {
next(err);
}
});

Den tydliga fördelen med detta är mindre belastning på datalagret. Under 1 minut kommer den att svara tillbaka med samma svar för samma parametrar. Utgången från funktionen products.getMultiple cachelagras i minnet i en minut. Detta gör svaren mycket snabba.

Exempel på anslutningspool med MySQL #

En annan sak som inte är möjlig på grund av en döende process i PHP är anslutningspooling. Enligt Wikipedia:

I programvaruteknik är en anslutningspool en cache av databasanslutningar som underhålls så att anslutningarna kan återanvändas när framtida förfrågningar till databasen krävs. Anslutningspooler används för att förbättra prestandan vid utförandet av kommandon i en databas.

Så, du har 5 anslutningar i en pool och om du vill köra 5 förfrågningar till databasen kan det göras samtidigt. Detta sparar tid både för att ansluta till databasen och för att köra frågan. Detta är lätt att göra i Node.js men inte lätt möjligt i PHP.

Var uppmärksam på antalet tillgängliga anslutningar och att hålla din anslutningspoolstorlek optimal.

Till exempel, om du använder Kubernetes och din applikation har 5 pods med en anslutningspoolstorlek på 2. Det innebär att din databas alltid kommer att ha 10 öppna anslutningar även om det inte utförs några frågor.

Tid för ett exempel på en anslutningspool med MySQL-databas med MySQL npm-modul:

var pool = mysql.createPool({
connectionLimit : 5,
host : 'example.org',
user : 'app',
password : 'pass',
database : 'schema'
});
for(var i=0;i<5;i++){
pool.query('SELECT 1 + 1 AS solution', function(err, rows, fields) {
if (err) {
throw err;
}
console.log(rows.solution); //Shows 2
});
}

Ovanstående kod kommer att köra samma fråga 5 gånger parallellt med 5 MySQL-anslutningar som tas från anslutningspoolen. Jag önskar att jag kunde göra detta i PHP direkt.

Men enligt min erfarenhet fungerar Node.js mycket bra med Mysql. Om du vill prova connection pooling med Mongo DB finns här ett Mongo-exempel.

Med en långvarig process måste du som utvecklare vara mer försiktig med minnesläckage och att göra hushållsgrejerna på ett bra sätt.

Det är här som Node.js för PHP-utvecklare behöver en rejäl omställning när det gäller att tänka på hur koden exekveras. Å andra sidan är detta en stor fördel i Node.js för PHP-utvecklare.

Debuggning är lättare i Node.js än i PHP #

Rad för rad koddebuggning är en viktig del av utvecklarens erfarenhet för alla programmeringsspråk. För att felsöka PHP-kod kan du använda tillägg som X-Debug med vissa IDE-inställningar. X-Debug är minst sagt utmanande att ställa in. Du måste installera det, aktivera tillägget. Efter det konfigurera det ordentligt med ett IDE som PHPStorm.

I grund och botten är enkelt det sista du kommer att säga om att få X-debug att fungera. Om inte allt är väl konfigurerat med en dockercontainer och IDE-inställningarna är också lätta att ladda.

Å andra sidan är det mycket enklare att köra node native debugger eller till och med ndb jämfört med PHP och X-debug. Med hjälp av VS Code är det så enkelt att felsöka en Node.js applikation att även en grottmänniska kan göra det.

Öppna Preferences > Settings och i sökrutan skriver du ”node debug”. Under fliken Tillägg bör det finnas ett tillägg med titeln ”Node debug”. Härifrån klickar du på den första rutan: Debug > Node: Auto Attach och ställ in rullgardinsrutan på ”on”. Nu är du nästan redo att börja arbeta. Ja, det är verkligen så enkelt.

Sätt sedan några brytpunkter på VS-kod med till exempel index.js och i terminalen skriver du node --inspect index.js.

BOOM! Din stegvisa Node.js-debugger fungerar bra i VS Code-redigeraren utan någon större ansträngning. En bra skillnad mot PHP, det finns ingen anledning att installera ett annat tillägg, aktivera det och konfigurera det för att kunna felsöka ett program. Inget behov av att installera ett extra tillägg är en fördel som finns i Node.js för PHP-utvecklare.

Nästa punkt handlar också om bättre utvecklarupplevelse när man uppgraderar även flera större versioner av språket.

Merre versionsuppgraderingar i Node.js är sömlös jämfört med PHP #

Att hoppa till och med flera större versioner i Node.js är en sömlös upplevelse. Att uppgradera från PHP 5.x till PHP 7.x är en vecka till månadslång process beroende på projektets storlek och komplexitet.

I min personliga erfarenhet har jag uppgraderat Node.js-mikrotjänster från version 0.12 till 4 tidigare. Nyligen uppgraderade jag en applikation från Node.js 10 till 14. Alla mina uppgraderingar av större versioner av Node.js har varit enkla.

Några mindre ändringar i package.json var de enda små problem jag stötte på. Efter distributionen fanns det sällan några problem som rörde kodkompatibilitet. Som en extra bonus var prestandan oftast bättre när man uppgraderade de större versionerna.

Å andra sidan har det inte varit lätt att uppgradera PHP. Uppgradering av mindre versioner för en applikation från PHP 5.4 till 5.6 var inte särskilt besvärligt. Men att gå från PHP 5.6 till 7.2 för en relativt stor applikation var en plåga. Det tog lång tid och krävde flera ändringar i composer.json. Det var också en svår uppgift att testa det. Den goda sidan av en större versionsuppgradering i PHP var säkert prestandaförbättringen.

Enbart en notering här, de PHP-applikationer jag arbetade med var äldre än Node.js-applikationerna. Din erfarenhet kan säkert vara annorlunda än min.

Dockerizing a Node.js application is a breeze compared to PHP #

Dockers popularitet har stadigt ökat under de senaste fem åren. Den har förändrat hur vi programvaruingenjörer arbetar sedan den släpptes. Du bör använda Docker även för lokal utveckling. Med detta i åtanke kan Dockerisering av en PHP-applikation vara en svår uppgift beroende på hur komponenterna är utformade och applikationens komplexitet. Omvänt är ansträngningen mindre för att dockerisera en Node.js-applikation och processen är en barnlek.

Nedan följer ett exempel på en dockerfil för en PHP Laravel-applikation med Apache.

FROM composer:1.9.0 as build
WORKDIR /app
COPY . /app
RUN composer global require hirak/prestissimo && composer install
FROM php:7.3-apache-stretch
RUN docker-php-ext-install pdo pdo_mysql
EXPOSE 8080
COPY --from=build /app /var/www/
COPY docker/000-default.conf /etc/apache2/sites-available/000-default.conf
COPY .env.example /var/www/.env
RUN chmod 777 -R /var/www/storage/ && \
echo "Listen 8080" >> /etc/apache2/ports.conf && \
chown -R www-data:www-data /var/www/ && \
a2enmod rewrite

Det som är bra med den här Docker-avbildningen för Laravel är att PHP är paketerad med apache i samma avbildning. Det kan diskuteras om detta är ett bättre sätt än att dela upp PHP och Apache i två docker-avbildningar.

Se också docker-bygget i flera steg i ovanstående docker-avbildning. Composer-installationen görs i en annan bild och resultatet kopieras till huvudbilden. Om vi hade använt PHP-FPM och Nginx i olika docker-avbildningar hade det varit mer komplicerat. Man skulle behöva hantera två olika docker-avbildningar.

Nu är det dags att ta en titt på en Node.js Dockerfile.

FROM node:14-alpine as base
WORKDIR /src
COPY package.json package-lock.json /src/
COPY . /src
EXPOSE 8080
FROM base as production
ENV NODE_ENV=production
RUN npm install
CMD
FROM base as dev
ENV NODE_ENV=development
RUN npm config set unsafe-perm true && npm install -g nodemon
RUN npm install
CMD

Då Node.js har en inbyggd webbserver är Dockerfilen mycket renare.

När du installerar node levereras npm med den. Detta eliminerar behovet av att installera paket i ett annat skede i dockerbygget.

I ovanstående dockerfil används flerstegs-dockerbygge för att separera produktions- och utvecklingsdockeravbildningar. Att ha pakethanteraren (npm) paketerad och att ha webbservern som en del av språket/runtime är något annat i Node.js för PHP-utvecklare. Om du är intresserad av att steg för steg docka ett Node.js-program följer du den här handledningen.

Slutsats #

När man använder Node.js för PHP-utvecklare krävs det en lätt förändring i tänkandet för att utnyttja Node.js krafter på ett bra sätt. Node.js är inte en silverkula. Det finns nackdelar och den behöver anpassas till olika sätt att exekvera kod.

Säkerligen finns det vissa fördelar med att använda Node.js för PHP-utvecklare som asynkron programmering och samtidighet. Andra fördelar härrör från Node.js-processen är långvarig.

Jag hoppas att det här inlägget hjälper dig som erfaren PHP-utvecklare att få ut mer av Node.js.

Lämna ett svar

Din e-postadress kommer inte publiceras.