Node.js dla programistów PHP: 5 praktycznych aspektów z przykładami kodu

Podczas gdy popularność Node.js rośnie, trakcja PHP spada. W tym kontekście, ten post będzie omawiał 5 praktycznych aspektów używania Node.js dla programistów PHP. Będą to rzeczy, o których nikt nie mówi ani nie pisze, czas zacząć działać.

  1. Node.js dla programistów PHP (nie Node.js vs PHP)
  2. Node.js dla programistów PHP strona praktyczna
    1. Wykonywanie kodu Node.js jest asynchroniczne i niesekwencyjne
      1. Node.js obiecuje możliwości
    2. Proces Node.js jest długotrwały, w przeciwieństwie do PHP
      1. Przykład memoizacji
      2. Przykład puli połączeń z MySQL
    3. Debugowanie jest łatwiejsze w Node.js niż w PHP
    4. Większe aktualizacje wersji w Node.js są bezproblemowe w porównaniu z PHP
    5. Dockerowanie aplikacji Node.js to pestka w porównaniu z PHP
  3. Podsumowanie

Node.js dla programistów PHP (nie Node.js vs PHP) #

Ten fragment jest listą rzeczy, które ty jako programista PHP musisz wiedzieć i nauczyć się, aby efektywnie używać Node.js. Wręcz przeciwnie, ten post nie jest Node.js vs PHP write up, gdzie PHP jest obalony. Używam obu języków. Zacząłem pisać więcej Node.js w 2016 roku. Kiedy zacząłem, napotkałem pewne trudności, ponieważ byłem przyzwyczajony do PHP w pracy przez ponad 7 lat przed tym. Była książka wydana pod koniec 2012 roku obejmująca Node.js dla programistów PHP.

Ten wpis na blogu nie będzie mówił o tym, czym jest PHP lub Node.js, możesz przeczytać o tym w innych postach. Nie będę również mówił zbyt wiele o Non-Blocking I/O lub pętli zdarzeń. Mimo to, niektóre z nich zostaną poruszone podczas omawiania praktycznych aspektów pisania dobrego kodu Node.js.

Node.js dla programistów PHP strona praktyczna #

PHP jest żywy od 1995 roku i podobno nadal jest używany przez 79.% stron internetowych monitorowanych przez W3tech (nie mogę powiedzieć, czy jest to cały internet). Więc szanse są bardzo wysokie, że używałeś PHP lub wdrożyłeś coś napisanego w PHP. Na przykład z rosnącym trendem:

WordPress jest używany przez 63,7% wszystkich stron internetowych, których system zarządzania treścią znamy. Jest to 39,0% wszystkich stron internetowych monitorowanych przez W3Tech.

Z drugiej strony, Node.js został wydany w 2009 roku. Główne firmy technologiczne, takie jak Linked In i Paypal zaczęły przyjmować go przez 2011 do 2013 z różnych powodów, takich jak mikroserwisy. Jak wynika z ankiety Stack Overflow dla deweloperów z 2020 roku:

Drugi rok z rzędu Node.js zajmuje pierwsze miejsce, ponieważ jest używany przez połowę respondentów.

Nie jest tajemnicą, że Node.js staje się bardzo popularny w ciągu ostatnich 5 lat.

Więc jako programista PHP, to jest 5 must-know praktycznych rzeczy, aby być świetnym inżynierem oprogramowania Node.js. Node.js dla programistów PHP jest podobny w pewnym sensie, ale także różni się w niektórych innych aspektach, które są opisane poniżej:

Wykonywanie kodu Node.js jest asynchroniczne i niesekwencyjne #

Jest to zachowanie, które oszukuje wielu programistów PHP. W PHP kod jest wykonywany sekwencyjnie, najpierw linia 1 potem 2, i tak dalej. W Javascript, a w szczególności w Node.js może być inaczej. Możesz potencjalnie umieszczać rzeczy w tle z dobrym wykorzystaniem obietnic i wywołań zwrotnych.

Poniżej znajduje się zmodyfikowany przykład kodu z wyjaśnieniem zaczerpniętym z mojego repo open source currency-api:

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 };
}

Jeśli przyjrzysz się bliżej, ten niewinnie wyglądający db.query w linii 3, został wepchnięty w tło. Więc będzie on wykonywany tak jak poniżej:

  1. Get rate
  2. Run insert query in the background
  3. Podczas gdy insert jest uruchamiany, funkcja zwraca już rate
  4. Jeśli wystąpi problem w zapytaniu insert, jest on rejestrowany w catch

Nie ma żadnego oryginalnego sposobu na zrobienie czegoś takiego w PHP. Jest to pierwsza rzecz, która przeszkadza programistom PHP. To sprawia, że trudniej jest zrozumieć Node.js dla programistów PHP. To asynchroniczne zachowanie wykonywania kodu również utrudnia znalezienie właściwego śladu stosu w przypadku błędów w Node.js.

Być szczerym, w 2020 roku możesz łatwo użyć async await. Nawet jeśli jest to cukier syntaktyczny na obietnicach, to sprawia, że programowanie asynchroniczne jest o wiele łatwiejsze. Kiedy zacząłem w erze Node 4/6 około 2016 roku z callbackami i obietnicami, to była zupełnie inna gra w piłkę. Mimo to uważaj, kiedy nie używać async-await (jak powyżej) i po prostu iść z obietnicami, następnie i złapać. Nie daj się jednak zaplątać w piekło obietnic w tym procesie. Piekło obietnic jest jak następna iteracja piekła callback.

Pro tip: Aby dowiedzieć się, które funkcje ES6 możesz użyć z jaką wersją Node.js, sprawdź to na node.green.

Inny Pro Tip:

Nawet wersje Node.js są LTS, nieparzyste nie są. Więc używaj Node 14 lub 16 nie 13 lub 15 w produkcji.

Głębiąc się nieco w niesekwencyjne wykonywanie, obietnice i moc, jaką ma, odgrywa tutaj ważną rolę. Możliwość robienia współbieżnych rzeczy jest świetna w Node.js i javascript w ogóle.

Możliwości obietnic Node.js #

Promises będąc asynchronicznym, możesz uruchomić je współbieżnie. Istnieją sposoby, aby to zrobić. Mógłbyś ścigać 3 obietnice i uzyskać wyniki z najszybszej z nich. Możesz nawet zrobić promise.all, gdzie jeśli jedna obietnica zostanie odrzucona, zatrzymuje całą operację. Proszę przeczytać więcej o Promise.race, promise.all i promise.any w tym świetnym porównaniu.

Mając to na uwadze, możesz spróbować innych bibliotek NPM, aby ograniczyć współbieżność obietnic lub nawet filtrować przez obietnice współbieżnie. Możesz zrobić niektóre z nich za pomocą ReactPHP. Ale nie jest on zawarty w natywnym PHP, nawet w PHP 8. To jest coś nowego do owinięcia głowy w Node.js dla programistów PHP.

Przejdźmy do następnego punktu, proces nie musi umrzeć w Node.js jak w PHP.

Proces Node.js jest długotrwały, w przeciwieństwie do PHP #

PHP ma umrzeć nie w tym sensie, że nie będzie używany. W tym sensie, że wszystkie procesy PHP muszą umrzeć. PHP nie jest zaprojektowane do długotrwałych zadań/procesów. W PHP, gdy przychodzi nowe żądanie HTTP, rozpoczyna się przetwarzanie, po odesłaniu odpowiedzi proces jest zabijany. Tak właśnie działa PHP. To tworzy zapotrzebowanie na FPM i inne serwery. Możesz argumentować, że PHP było bezserwerowe z założenia 20+ lat temu. Pozostawiam to tobie.

Po drugiej stronie, Node.js jest procesem długo działającym. Umożliwia to udostępnianie informacji między żądaniami, ponieważ ten sam serwer / proces obsługuje wiele żądań. Dzięki długo działającemu procesowi możesz łatwo wykorzystać takie rzeczy jak memoization na pamięci i łączenie puli połączeń dla bazy danych. Otwiera to inne możliwości, jak na przykład liczenie liczby współbieżnych żądań na tym procesie.

Przykład memoizacji #

Jeśli nie znasz memoizacji.

Memoizacja jest funkcją wyższego rzędu, która buforuje inną funkcję. Może zamienić niektóre powolne funkcje w szybkie. Zapisuje ona wynik wywołania funkcji po pierwszym razie do cache’u, więc jeśli wywołasz ją ponownie z tymi samymi argumentami, znajdzie go w cache’u.

Może być używana w Node.js, ale nie w PHP natywnie. Niektóre obejścia są możliwe w PHP, jak zapisywanie wartości zwracanej funkcji w Redis.

Poniżej znajduje się próbka kodu memoizacji na trasie ekspresowej z 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);
}
});

Jasną zaletą tego jest mniejsze obciążenie magazynu danych. Przez 1 minutę będzie odpowiadać z powrotem z tą samą odpowiedzią dla tych samych parametrów. Dane wyjściowe funkcji products.getMultiple są buforowane w pamięci przez minutę. To sprawia, że odpowiedzi są bardzo szybkie.

Przykład puli połączeń z MySQL #

Inną rzeczą, która nie jest możliwa z powodu umierającego procesu w PHP jest łączenie połączeń. Jak podaje Wikipedia:

W inżynierii oprogramowania, pula połączeń jest pamięcią podręczną połączeń z bazą danych utrzymywaną tak, że połączenia mogą być ponownie użyte, gdy przyszłe żądania do bazy danych są wymagane. Pule połączeń są używane w celu zwiększenia wydajności wykonywania poleceń na bazie danych.

Więc, będziesz miał 5 połączeń w puli i jeśli chcesz uruchomić 5 zapytań do bazy danych, może to być wykonane współbieżnie. Oszczędza to czas zarówno na łączenie się z bazą danych, jak i na uruchamianie zapytań. Jest to łatwe do zrobienia w Node.js, ale nie jest łatwo możliwe w PHP.

Pamiętaj o liczbie dostępnych połączeń i utrzymuj optymalny rozmiar puli połączeń.

Na przykład, jeśli używasz Kubernetes i twoja aplikacja ma 5 strąków z rozmiarem puli połączeń 2. Oznacza to, że twoja baza danych zawsze będzie miała 10 otwartych połączeń, nawet jeśli nie są wykonywane żadne zapytania.

Czas na przykład puli połączeń z bazą danych MySQL z modułem MySQL npm:

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
});
}

Powyższy kod uruchomi to samo zapytanie 5 razy równolegle z 5 połączeniami MySQL pobranymi z puli połączeń. Chciałbym móc to zrobić w PHP po wyjęciu z pudełka.

W moim doświadczeniu, Node.js działa bardzo dobrze z Mysql. Jeśli chcesz wypróbować łączenie puli z Mongo DB, tutaj jest przykład Mongo.

W przypadku długotrwałego procesu jako deweloper musisz być bardziej ostrożny z wyciekami pamięci i robieniem rzeczy porządkowych dobrze.

To jest miejsce, w którym Node.js dla programistów PHP potrzebuje dość dużo przesunięcia w myśleniu o tym, jak kod jest wykonywany. Z drugiej strony, jest to wielka zaleta Node.js dla programistów PHP.

Debugowanie jest łatwiejsze w Node.js niż w PHP #

Debugowanie kodu linia po linii jest ważną częścią doświadczenia dewelopera dla każdego języka programowania. Aby debugować kod PHP, możesz użyć dodatków takich jak X-Debug z pewnymi ustawieniami IDE. X-Debug jest, delikatnie mówiąc, trudny do skonfigurowania. Musisz go zainstalować, włączyć rozszerzenie. Następnie skonfigurować go poprawnie za pomocą IDE takiego jak PHPStorm.

Podsumowując, łatwość jest ostatnią rzeczą, którą powiesz o uruchomieniu X-debug. Chyba, że wszystko jest dobrze skonfigurowane z kontenerem docker i ustawienia IDE są również łatwe do załadowania.

Z drugiej strony, uruchomienie natywnego debuggera node lub nawet ndb jest o wiele łatwiejsze w porównaniu do PHP i X-debug. Przy użyciu VS Code, debugowanie aplikacji Node.js jest tak proste, że nawet jaskiniowiec może to zrobić.

Otwórz Preferencje > Ustawienia i w polu wyszukiwania wpisz „node debug”. W zakładce Rozszerzenia powinno być jedno rozszerzenie o tytule „Node debug”. Stąd, kliknij pierwsze pole: Debug > Node: Auto Attach i ustaw drop-down na „on”. Teraz jesteś już prawie gotowy do pracy. Tak, to naprawdę jest takie proste.

Następnie ustaw kilka punktów przerwania na kodzie VS z powiedzmy index.js i w terminalu wpisz node --inspect index.js.

BOOM! Twój krok po kroku debugger Node.js działa dobrze w edytorze VS Code bez większego wysiłku. Dobra różnica w stosunku do PHP, nie ma potrzeby instalowania innego rozszerzenia, włączania go i konfigurowania, aby móc debugować program. Brak potrzeby instalowania dodatkowego rozszerzenia jest korzyścią znalezioną w Node.js dla programistów PHP.

Kolejny punkt dotyczy również lepszego doświadczenia programisty podczas aktualizacji nawet wielu głównych wersji języka.

Major version upgrades in Node.js is seamless over PHP #

Skakanie nawet wielu głównych wersji w Node.js jest bezproblemowym doświadczeniem. Aktualizacja z PHP 5.x do PHP 7.x to proces trwający od tygodnia do miesiąca, w zależności od wielkości i złożoności projektu.

W moim osobistym doświadczeniu uaktualniłem mikroserwisy Node.js z wersji 0.12 do 4 w przeszłości. Ostatnio uaktualniłem aplikację z Node.js 10 do 14. Wszystkie moje główne aktualizacje wersji Node.js były łatwe.

Kilka drobnych zmian package.json było jedynymi małymi problemami, które napotkałem. Po wdrożeniu rzadko pojawiały się jakiekolwiek problemy związane z kompatybilnością kodu. Dodatkowym plusem była wydajność, która zazwyczaj była lepsza przy aktualizacji do większych wersji.

Z drugiej strony, aktualizacja PHP nie była łatwa. Aktualizacja wersji mniejszej dla aplikacji z PHP 5.4 do 5.6 nie była zbyt kłopotliwa. Ale przejście z PHP 5.6 do 7.2 dla relatywnie dużej aplikacji było prawdziwą męczarnią. Zajmowało to dużo czasu i wymagało wielu zmian w pliku composer.json. Testowanie było również trudnym zadaniem. Dobrą stroną dużej aktualizacji wersji PHP był z pewnością wzrost wydajności.

Przypominam, że aplikacje PHP, z którymi pracowałem były starsze niż aplikacje Node.js. Twoje doświadczenie z pewnością może być inne niż moje.

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

Popularność Dockera stale rosła w ciągu ostatnich 5 lat. Zmienił sposób, w jaki my, inżynierowie oprogramowania, pracujemy od czasu jego wydania. Powinieneś używać Dockera również do lokalnego rozwoju. Mając to na uwadze, Dockerizing aplikacji PHP może być trudnym zadaniem, w zależności od tego, jak rozłożone są komponenty i jak złożona jest aplikacja. Odwrotnie, w przypadku dockerowania aplikacji Node.js wysiłek jest mniejszy, a proces jest prosty.

Poniżej znajduje się przykład pliku docker dla aplikacji PHP Laravel z 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

Dobrą rzeczą w tym obrazie Dockera dla Laravel jest to, że PHP jest połączone z apache w tym samym obrazie. Można się spierać, czy jest to lepszy sposób niż rozdzielenie PHP i Apache na dwa obrazy docker.

Zauważ także wieloetapowy build docker w powyższym obrazie docker. Instalacja Composera jest wykonywana w innym obrazie, a dane wyjściowe są kopiowane do głównego obrazu. Gdybyśmy użyli PHP-FPM i Nginx w różnych obrazach dockera, byłoby to bardziej skomplikowane. Należałoby zarządzać dwoma różnymi obrazami docker.

Teraz czas przyjrzeć się plikowi Dockerfile Node.js.

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

Jako że Node.js ma wbudowany serwer WWW, plik Dockerfile jest znacznie czystszy.

Gdy instalujesz node, npm jest z nim w pakiecie. Eliminuje to potrzebę instalowania pakietów na innym etapie budowania dockera.

W powyższym pliku Dockerfile wieloetapowy build dockera jest używany do oddzielenia produkcyjnych i rozwojowych obrazów dockera. Posiadanie menedżera pakietów (npm) w pakiecie i posiadanie serwera WWW jako części języka/runtime jest czymś innym w Node.js dla programistów PHP. Jeśli jesteś zainteresowany Dockeringiem aplikacji Node.js krok po kroku, skorzystaj z tego tutoriala.

Wniosek #

Korzystanie z Node.js dla programistów PHP wymaga lekkiej zmiany sposobu myślenia, aby dobrze wykorzystać możliwości Node.js. Node.js nie jest srebrną kulą. Ma wady i wymaga dostosowania do różnych sposobów wykonywania kodu.

Z pewnością istnieją pewne korzyści z używania Node.js dla programistów PHP, takie jak programowanie asynchroniczne i współbieżność. Inne zalety wynikają z Node.js proces jest długotrwały.

Mam nadzieję, że ten post pomoże Ci uzyskać więcej z Node.js jako doświadczony programista PHP.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.