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ć.
- Node.js dla programistów PHP (nie Node.js vs PHP)
- Node.js dla programistów PHP strona praktyczna
- Wykonywanie kodu Node.js jest asynchroniczne i niesekwencyjne
- Node.js obiecuje możliwości
- Proces Node.js jest długotrwały, w przeciwieństwie do PHP
- Przykład memoizacji
- Przykład puli połączeń z MySQL
- Debugowanie jest łatwiejsze w Node.js niż w PHP
- Większe aktualizacje wersji w Node.js są bezproblemowe w porównaniu z PHP
- Dockerowanie aplikacji Node.js to pestka w porównaniu z PHP
- Wykonywanie kodu Node.js jest asynchroniczne i niesekwencyjne
- 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:
- Get rate
- Run insert query in the background
- Podczas gdy insert jest uruchamiany, funkcja zwraca już rate
- 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.