mirror of
https://github.com/goldbergyoni/nodebestpractices.git
synced 2025-10-28 03:25:55 +08:00
Merge branch 'master' into japanese-translation
This commit is contained in:
27
sections/errorhandling/apmproducts.basque.md
Normal file
27
sections/errorhandling/apmproducts.basque.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Aurkitu erroreak eta jardunik gabeko uneak APM produktuak erabiliz
|
||||
|
||||
### Azalpen paragrafoa
|
||||
|
||||
Salbuespena != Errorea. Erroreen kudeaketa tradizionalak kodearekin erlazionatutako arazotzat hartzen ditu salbuespenak, baina aplikazioen erroreak formularioko kode bide motelen, APIen jardunik gabeko uneen eta baliabide konputazionalen gabezien ondorio izan daitezke. Horra non APM produktuak oso erabilgarriak diren, 'lurperatutako' askotariko gaiak modu proaktiboan detektatzeko aukera ematen baitute gutxieneko konfigurazioarekin. APM produktuen ohiko funtzionalitateen artean daude, adibidez, HTTP APIak erroreak bidaltzen dituenean alerta jotzea, APIaren erantzunaren denbora aurretik zehaztutako denbora muga baino luzeagoa denean antzematea, ‘kode usainak’ hautematea, monitorizazio zerbitzariaren baliabideentzako funtzionalitateak, operazio inteligentziadun panelak (dashboard) IT metrikekin eta beste funtzionalitate batzuk oso erabilgarriak direnak. Hornitzaile gehienek dohaineko plana eskaintzen dute.
|
||||
|
||||
### Wikipedia APMri buruz
|
||||
|
||||
Informazioaren teknologien eta sistemen kudeaketaren alorretan, Application Performance Management (APM) software aplikazioen errendimendu eta erabilgarritasunaren monitorizazio eta kudeaketa da. APM aplikazioen errendimendu arazo konplexuak atzeman eta diagnostikatzen saiatzen da, esperotako zerbitzu maila mantentzeko. APM "IT metrikak negozioaren esanahira ([hau da,] balioa)" itzultzea da. Produktu eta segmentu nagusiak. APM "IT metrikak negozioaren esanahira ([hau da,] balioa)" itzultzea da. Produktu eta segmentu nagusiak.
|
||||
|
||||
### APM merkatua ulertzen
|
||||
|
||||
APM produktuek 3 segmentu nagusi dituzte:
|
||||
|
||||
1. Webgune edo APIen monitorizazioa, martxan egondako denbora eta errendimuendua HTTP eskaeren bidez etengabe monitorizatzen dituzten kanpo zerbitzuak. Minutu gutxi batzuetan ezar daiteke. Hurrengo hauek dira aukeratutako lehiakide batzuk: [Pingdom](https://www.pingdom.com/), [Uptime Robot](https://uptimerobot.com/), eta [New Relic](https://newrelic.com/application-monitoring)
|
||||
|
||||
2. Kodearen instrumentazioa, kode motelaren atzematea, salbuespenen estadistikak, errendimenduaren monitorizazioa eta holako beste funtzionalitate batzuk erabiltzeko agente bat aplikazioan txertatzea eskatzen duen produktu familia da. Hurrengo hauek dira aukeratutako lehiakide batzuk: New Relic, App Dynamics
|
||||
|
||||
3. Adimen operatiboaren panela produktuen linea bat da, operazio taldeari metrika eta eduki aukeratuak eskaintzen dizkiona eta aplikazioaren errendimendua zein den jakitera behartzen duena. Horrek informazio iturri anitz (aplikazioen erregistroak, DB erregistroak, zerbitzarien erregistroa, etab.) eta aurrez aurreko arbelaren diseinua batzea eskatzen du. Hurrengo hauek dira aukeratutako lehiakide batzuk: [Datadog](https://www.datadoghq.com/), [Splunk](https://www.splunk.com/), [Zabbix](https://www.zabbix.com/)
|
||||
|
||||
### Adibidea: UpTimeRobot.Com: webguneak monitorizatzeko panela
|
||||
|
||||

|
||||
|
||||
### Adibidea: AppDynamics.Com: hasieratik amaierarainoko monitorizazioa kode instrumentazioarekin konbinatutakoa
|
||||
|
||||

|
||||
119
sections/errorhandling/asyncerrorhandling.basque.md
Normal file
119
sections/errorhandling/asyncerrorhandling.basque.md
Normal file
@ -0,0 +1,119 @@
|
||||
# Erabili Async-Await edo errore asinkronoak kudeatzeko promesak
|
||||
|
||||
### Azalpen paragrafoa
|
||||
|
||||
Callbackak ez dira kudea errazak programatzaile gehienek ez dituzte ondo ezagutzen eta. Callbackek etengabeko errore egiaztatzea eskatzen dute, kode korapilotsua jasanaraziz eta kodigoaren fluxuaren ulergarritasuna zailduz. BlueBird, async, eta Q bezalako promesa liburutegiek kodigo estilo estandarra RETURN eta THROW erabiliz paketatzen dute, programaren fluxua kontrolatzeko. Zehazki, kodigo nagusia funtzio bakoitzean erroreak kuadeatzetik askatzea ahalbidetzen duen try-catch errore kudeaketa estilo gogokoena onartzen dute
|
||||
|
||||
### Kode adibidea: promesen erabilera erroreak antzemateko
|
||||
|
||||
```javascript
|
||||
return aFuntzioa()
|
||||
.then(bFuntzioa)
|
||||
.then(cFuntzioa)
|
||||
.then(dFuntzioa)
|
||||
.catch((errorea) => logger.error(errorea))
|
||||
.then(betiExekutatuFuntzioHau);
|
||||
```
|
||||
|
||||
### Kode adibidea: async/awaiten erabilera erroreak antzemateko
|
||||
|
||||
```javascript
|
||||
async function exekutatuAtazaAsinkronoBat() {
|
||||
try {
|
||||
const aBalioa = await aFuntzioa();
|
||||
const bBalioa = await bFuntzioa(aBalioa);
|
||||
const cBalioa = await cFuntzioa(bBalioa);
|
||||
return await dFuntzioa(cBalioa);
|
||||
} catch (errorea) {
|
||||
logger.error(errorea);
|
||||
} finally {
|
||||
await betiExekutatuFuntzioHau();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Anti ereduaren kode adibidea: callbackaren estiloko errore kudeaketa
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
datuakEskuratu(parametrorenBat, function (errorea, emaitza) {
|
||||
if (errorea !== null) {
|
||||
// bueltatutako callback funtzioa deitzea moduko zerbait egin eta errorea pasatu
|
||||
datuGehiagoEskuratu(a, function (errorea, emaitza) {
|
||||
if (errorea !== null) {
|
||||
// bueltatutako callback funtzioa deitzea moduko zerbait egin eta errorea pasatu
|
||||
datuGehiagoEskuratu(b, function (c) {
|
||||
datuGehiagoEskuratu(d, function (e) {
|
||||
if (errorea !== null) {
|
||||
// ulertu duzu ideia?
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
datuakEskuratu(
|
||||
parametrorenBat,
|
||||
function (errorea: Error | null, aEmaitza: ResultA) {
|
||||
if (errorea !== null) {
|
||||
// bueltatutako callback funtzioa deitzea moduko zerbait egin eta errorea pasatu
|
||||
datuGehiagoEskuratu(
|
||||
aEmaitza,
|
||||
function (errorea: Error | null, bEmaitza: ResultB) {
|
||||
if (errorea !== null) {
|
||||
// bueltatutako callback funtzioa deitzea moduko zerbait egin eta errorea pasatu
|
||||
datuGehiagoEskuratu(bEmaitza, function (cEmaitza: ResultC) {
|
||||
datuGehiagoEskuratu(
|
||||
cEmaitza,
|
||||
function (errorea: Error | null, d: ResultD) {
|
||||
if (errorea !== null) {
|
||||
// ulertu duzu ideia?
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Blogeko aipua: "Promesekin arazo bat dugu"
|
||||
|
||||
pouchdb.com blogetik hartua
|
||||
|
||||
> ……Izatez, callbackek zerbait oraindik maltzurragoa egiten dute: pilaz gabetzen gaituzte, programazio lengoaietan sarri egintzat jotzen duguna. Kodea pila gabe idaztea kotxe bat freno pedalik gabe gidatzea bezala da: ez zara konturatzen zein puntura arte
|
||||
behar duzun erabiltzen saiatu eta ez dagoela konturatzen zaren momentura arte. Promesen helburu nagusia da asinkronoa (async) erabiltzean galdutako lengoaien oinarri guztiak berreskuratzea: return, throw eta pila. Baina promesak modu egokian erabiltzen jakin beharra dago beraiei probetxua ateratzeko.
|
||||
|
||||
### Blogeko aipua: "Promesen metodoa askoz ere trinkoagoa da"
|
||||
|
||||
gosquared.com blogetik hartua
|
||||
|
||||
> ………Promesen metodoa askoz ere trinkoagoa, argiagoa eta idatzeko azkarragoa da. Errore edo salbuespen bat gertatzen bada, .catch() kudeatzaile bakar batek maneiatzen du.Errore guztiak kudeatzeko leku bakarra edukitzeak erroreen egiaztatzea lanaren fase bakoitzean idatzi beharrik ez dagoela adierazten du.
|
||||
|
||||
### Blogeko aipua: "Promisak jatorrizko ES6 dira, eta sorgailuekin erabil daitezke"
|
||||
|
||||
StrongLoop blogetik hartua
|
||||
|
||||
> ….Callbackek erroreen kudeaketa istorio kaskarra dute. Promesak hobeak dira. Promesekin, erabili Expressen errore kudeaketa kapsulatua eta horrela salbuespenen bat ez antzemateko aukerak murriztuko dituzu. Promesak jatorriz ES6ak dira, eta generatzaileekin eta ES7ren async/await bezalako proposamenekin erabil daitezke Babel bezalako konpilatzaileetan.
|
||||
|
||||
### Blogeko aipua: "Ohiko fluxu kontrol erregularren egitura guzti horiek guztiz apurtuta daude"
|
||||
|
||||
Benno’s blogetik hartua
|
||||
|
||||
> ……Asinkronoaren, hau da, callbacketan oinarritutako programazioaren gauza hoberenetako bat da ohituta zauden fluxu kontrol erregularren egitura guzti horiek guztiz apurtuta daudela. Hala ere, salbuespenen kudeaketa da niretzat apurtuen dagoena. Javascriptek nahiko try…catch egitura ezaguna hornitzen du. Salbuespenen arazoa da, erroreak pila batean ekiditeko aukera ona eman arren, errorea beste pila batean gertatzen bada guztiz alferrikakoak izaten bukatzen dutela…
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
### Объяснение в один абзац
|
||||
|
||||
Обратные вызовы плохо масштабируются, так как большинство программистов не знакомы с ними. Они заставляют проверять ошибки повсюду, имеют дело с неприятным вложением кода и затрудняют анализ потока кода. Библиотеки Promise, такие как BlueBird, async и Q, упаковывают стандартный стиль кода, используя RETURN и THROW для управления потоком программы. В частности, они поддерживают любимый стиль обработки ошибок try-catch, который позволяет освободить путь к основному коду от ошибок в каждой функции
|
||||
Обратные вызовы плохо масштабируются, так как большинство программистов не знакомы с ними. Они заставляют проверять ошибки повсюду, иметь дело с неприятной вложенностью кода и затрудняют анализ потока кода. Библиотеки обещаний (promise), такие как BlueBird, async и Q, упаковывают стандартный стиль кода, используя RETURN и THROW для управления потоком программы. В частности, они поддерживают наилучший стиль обработки ошибок try-catch, который позволяет освободить основной код от обработки ошибок в каждой функции.
|
||||
|
||||
### Пример кода – использование обещаний для отлова ошибок
|
||||
|
||||
@ -15,7 +15,6 @@ return functionA()
|
||||
.then(alwaysExecuteThisFunction)
|
||||
```
|
||||
|
||||
|
||||
### Пример кода - использование async/await для отлова ошибок
|
||||
|
||||
```javascript
|
||||
@ -34,7 +33,7 @@ async function executeAsyncTask () {
|
||||
}
|
||||
```
|
||||
|
||||
### Антипаттерн. Обработка ошибок в стиле обратного вызова
|
||||
### Антипаттерн. Обработка ошибок в callback-стиле
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
@ -42,14 +41,14 @@ async function executeAsyncTask () {
|
||||
```javascript
|
||||
getData(someParameter, function(err, result) {
|
||||
if(err !== null) {
|
||||
// do something like calling the given callback function and pass the error
|
||||
// вызываем коллбек функцию и передаем ошибку
|
||||
getMoreData(a, function(err, result) {
|
||||
if(err !== null) {
|
||||
// do something like calling the given callback function and pass the error
|
||||
// вызываем коллбек функцию и передаем ошибку
|
||||
getMoreData(b, function(c) {
|
||||
getMoreData(d, function(e) {
|
||||
if(err !== null ) {
|
||||
// you get the idea?
|
||||
// вы поняли идею?
|
||||
}
|
||||
})
|
||||
});
|
||||
@ -66,14 +65,14 @@ getData(someParameter, function(err, result) {
|
||||
```typescript
|
||||
getData(someParameter, function(err: Error | null, resultA: ResultA) {
|
||||
if(err !== null) {
|
||||
// do something like calling the given callback function and pass the error
|
||||
// вызываем коллбек функцию и передаем ошибку
|
||||
getMoreData(resultA, function(err: Error | null, resultB: ResultB) {
|
||||
if(err !== null) {
|
||||
// do something like calling the given callback function and pass the error
|
||||
// вызываем коллбек функцию и передаем ошибку
|
||||
getMoreData(resultB, function(resultC: ResultC) {
|
||||
getMoreData(resultC, function(err: Error | null, d: ResultD) {
|
||||
if(err !== null) {
|
||||
// you get the idea?
|
||||
// вы поняли идею?
|
||||
}
|
||||
})
|
||||
});
|
||||
@ -90,20 +89,20 @@ getData(someParameter, function(err: Error | null, resultA: ResultA) {
|
||||
|
||||
> … На самом деле, обратные вызовы делают что-то еще более зловещее: они лишают нас стека, что мы обычно принимаем как должное в языках программирования. Написание кода без стека очень похоже на вождение автомобиля без педали тормоза: вы не понимаете, насколько сильно оно вам нужно, пока не дойдете до него, а его там нет. Весь смысл обещаний состоит в том, чтобы вернуть нам языковые основы, которые мы потеряли при асинхронности: возврат, выброс и стек. Но вы должны знать, как правильно использовать обещания, чтобы воспользоваться ими.
|
||||
|
||||
### Цитата блога: "Метод обещаний гораздо более компактен"
|
||||
### Цитата блога: "Подход с обещаниями гораздо более компактен"
|
||||
|
||||
Из блога gosquared.com
|
||||
|
||||
> … Метод обещаний гораздо компактнее, понятнее и быстрее для написания. Если ошибка или исключение происходят в любом из операций, они обрабатываются одним обработчиком .catch(). Наличие единого места для обработки всех ошибок означает, что вам не нужно писать проверку ошибок для каждого этапа работы.
|
||||
> … Подход с обещаниями гораздо компактнее, понятнее и быстрее для написания. Если ошибка или исключение происходят в любой из операций, они обрабатываются одним обработчиком .catch(). Наличие единого места для обработки всех ошибок означает, что вам не нужно писать проверку ошибок для каждого этапа работы.
|
||||
|
||||
### Цитата блога: "Обещания являются родными ES6, могут использоваться с генераторами"
|
||||
### Цитата блога: "Обещания являются нативными в ES6, могут использоваться с генераторами"
|
||||
|
||||
Из блога StrongLoop
|
||||
|
||||
> … Обратные вызовы имеют паршивую историю обработки ошибок. Обещания лучше. Объедините встроенную обработку ошибок в Express с обещаниями и значительно снизьте вероятность возникновения необработанного исключения. Обещания являются родными ES6, могут использоваться с генераторами, а предложения ES7, такие как async/await, через компиляторы, такие как Babel.
|
||||
> … Обратные вызовы имеют паршивую историю обработки ошибок. Обещания лучше. Объедините встроенную обработку ошибок в Express с обещаниями и значительно снизьте вероятность возникновения необработанного исключения. Обещания являются нативными в ES6, могут использоваться с генераторами, а proposals из ES7, такие как async/await, могут использоваться через компиляторы, такие как Babel.
|
||||
|
||||
### Цитата из блога: "Все те обычные конструкции управления потоком, к которым вы привыкли, полностью разрушены"
|
||||
|
||||
Из блога Бенно
|
||||
|
||||
> … Одно из лучших преимуществ асинхронного программирования на основе обратного вызова состоит в том, что в основном все эти обычные конструкции управления потоком, к которым вы привыкли, полностью разрушены. Тем не менее, я считаю, что больше всего разрушения коснулись обработки исключений. Javascript предоставляет довольно знакомую конструкцию try…catch для работы с исключениями. Проблема с исключениями состоит в том, что они обеспечивают отличный способ сокращения ошибок в стеке вызовов, но в конечном итоге оказываются совершенно бесполезными, если ошибка происходит в другом стеке…
|
||||
> … Одно из лучших преимуществ асинхронного программирования на основе обратного вызова состоит в том, что в основном все эти обычные конструкции управления потоком, к которым вы привыкли, полностью разрушены. Тем не менее, я считаю, что больше всего разрушения коснулась обработка исключений. Javascript предоставляет довольно знакомую конструкцию try…catch для работы с исключениями. Проблема с исключениями состоит в том, что они обеспечивают отличный способ сокращения ошибок в стеке вызовов, но в конечном итоге оказываются совершенно бесполезными, если ошибка происходит в другом стеке…
|
||||
@ -0,0 +1,88 @@
|
||||
# Atzeman kudeatu gabeko agintzen arbuioak
|
||||
|
||||
<br/><br/>
|
||||
|
||||
### Azalpen paragrafoa
|
||||
|
||||
Normalean, Node.js/Express aplikazio kode moderno gehienek promesen barruan funtzionatzen dute, .then kudeatzailearen, callback funtzio baten edota catch bloke baten barruan. Harrigarria bada ere, garatzaile batek .catch klausula bat gehitu zuela gogoratu ezean, leku hauetan jaurtitako erroreak ez dira uncaughtException ebentu kudeatzaileaz kudeatuak izaten, eta desagertu egiten dira. Noderen bertsio berrienek ohartarazpen mezu bat gehitu dute tratatu gabeko errefusa agertzen denean; egia da horrek, gauzak ondo ez doazenean, ohartzen lagun dezakeela, baina argi dago ez dela erroreak kudeatzeko modu egokia. Konponbide samurrena da ez ahaztea promesa kateko dei bakoitzaren barruan .catch klausula erabiltzen eta errore kudeatzaile zentralizatu batera desbideratzea. Hala ere, hauskorra da erroreak kudeatzeko estrategia garatzailearen diziplinan soilik oinarritzea. Ondorioz, oso gomendagarria da atzera egite dotorea erabiltzea eta `process.on('unhandledRejection', callback)`ra harpidetzea, horrek ziurtatuko baitu promesa erroreek, bere tratamendua izango dutela, lokalki kudeatzen ez badira.
|
||||
|
||||
<br/><br/>
|
||||
|
||||
### Kode adibidea: errore hauek ez ditu inolako errore kudeatzailek atzemango (unhandledRejection-ek izan ezik)
|
||||
|
||||
```javascript
|
||||
DAL.berreskuratuErabiltzaileaIdBidez(1).then((johnSnow) => {
|
||||
// errore hau desagertu egingo da
|
||||
if (johnSnow.bizirikDago === false) throw new Error("ahhhh");
|
||||
});
|
||||
```
|
||||
|
||||
<br/><br/>
|
||||
|
||||
### Kode adibidea: kudeatu gabeko eta baztertutako promesak atzematen
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
process.on("unhandledRejection", (arrazoia, p) => {
|
||||
// Kudeatu gabeko baztertutako promesa bat harrapatu dut,
|
||||
// iada kudeatu gabeko erroreentzat atzera-egite kudeatzailea dugunez (begiratu beherago),
|
||||
// utzi jaurtitzen eta utzi berari hori kudeatzen
|
||||
throw arrazoia;
|
||||
});
|
||||
|
||||
process.on("uncaughtException", (errorea) => {
|
||||
// Aurretik inoiz kudeatu gabeko errorea jaso berri dut, hau kudeatzeko eta berrekite bat beharrezkoa den erabakitzeko garaia da
|
||||
erroreKudeaketa.kudeatzailea.erroreaKudeatu(errorea);
|
||||
if (!erroreKudeaketa.kudeatzailea.erroreFidagarriaDa(errorea))
|
||||
process.exit(1);
|
||||
});
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
process.on("unhandledRejection", (arrazioa: string, p: Promise<any>) => {
|
||||
// Kudeatu gabeko baztertutako promesa bat harrapatu dut,
|
||||
// iada kudeatu gabeko erroreentzat atzera-egite kudeatzailea dugunez (begiratu beherago),
|
||||
// utzi jaurtitzen eta utzi berari hori kudeatzen
|
||||
throw arrazoia;
|
||||
});
|
||||
|
||||
process.on("uncaughtException", (errorea: Error) => {
|
||||
// Aurretik inoiz kudeatu gabeko errorea jaso berri dut, hau kudeatzeko eta berrekite bat beharrezkoa den erabakitzeko garaia da
|
||||
erroreKudeaketa.kudeatzailea.erroreaKudeatu(errorea);
|
||||
if (!erroreKudeaketa.kudeatzailea.erroreFidagarriaDa(errorea))
|
||||
process.exit(1);
|
||||
});
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<br/><br/>
|
||||
|
||||
### Blogeko aipua: ""Erroreren bat egiteko gai bazara, momenturen batean egin egingo duzu"
|
||||
|
||||
James Nelson blogetik hartua
|
||||
|
||||
> Proba dezagun zure ulermena. Hauetako zeinek uste duzu erakutsiko duela errore bat kontsolan?
|
||||
|
||||
```javascript
|
||||
Promise.resolve("agindutako balioa").then(() => {
|
||||
throw new Error("errorea");
|
||||
});
|
||||
|
||||
Promise.reject("errore balioa").catch(() => {
|
||||
throw new Error("errorea");
|
||||
});
|
||||
|
||||
new Promise((resolve, reject) => {
|
||||
throw new Error("errorea");
|
||||
});
|
||||
```
|
||||
|
||||
> Ez dakit zer pentsatzen duzun, baina nire erantzuna da guztietan bistaratuko dela erroreren bat, eta errealitatea da JavaScript ingurune moderno gehienek kasu hauetako batentzat ere ez dituztela erroreak bistaratuko. Gizakien arazoa da, erroreen bat egiteko gai bazara, momenturen batean egingo duzula. Hori argi edukita, begibistakoa dirudi gauzak diseinatu behar direla erroreen erruz ahalik eta gutxien hondatzeko, eta horrek erroreak beti kudeatu beharra dagoela esan nahi du, alde batera utzi beharrean.
|
||||
175
sections/errorhandling/centralizedhandling.basque.md
Normal file
175
sections/errorhandling/centralizedhandling.basque.md
Normal file
@ -0,0 +1,175 @@
|
||||
# Kudeatu erroreak gune bakar batean, Express middleware erabili partez
|
||||
|
||||
### Azalpen paragrafoa
|
||||
|
||||
Errore kudeaketarako ardura bakarreko objektu bat ez izateak, errore garrantzitsuak ezkutatzeko aukerak ugaritzen ditu kudeaketa ezegoki baten eraginpean. Errore kudeaketarako objektua, errorea begibistako bihurtzearen arduradun da, adibidez, egoki formateatutako erregistro batean idatziz, ebentuak [Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/), edota [Raygun](https://raygun.com/) bezalako monitorizazio sistemaren batera bidaliz. [Express](http://expressjs.com/en/guide/error-handling.html#writing-error-handlers) bezalako web framework gehienak, errore kudeaketa middleware mekanismo bat proposatzen dute. Errore kudeaketa fluxu tipiko bat hau izan daiteke: moduluren batek errore bat jaurtitzen du -> API routerrak errorea harrapatzen du -> errorea middlewarera hedatzen du, (adibidez Express edo KOA), zeinek erroreak harrapatzeko ardura duen -> errore kudeatzaile zentralizatu bati deitzen zaio -> middlewareari esaten zaio ia errore hau konfiantzazkoa den (ez operazio errorea) aplikazioa dotoreki berrekiteko. Kontutan izan Express midelwarean erroreak kudeatzea praktika arrunta dela, okerra izan arren. Hau egiteak ez ditu kontutan hartzen weba ez diren bestelako interfazeetako erroreak.
|
||||
|
||||
### Kode adibidea: ohiko errore fluxua
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
// DAL (Data Access Layer) geruza, ez ditugu erroreak hemen kudeatzen
|
||||
DB.gehituDokumentua(bezeroBerria, (errorea, emaitza) => {
|
||||
if (errorea)
|
||||
throw new Error('Errore azalpen bikaina dator hemen', bestelako parametro erabilgarri batzuk)
|
||||
});
|
||||
|
||||
// API bide kodea, errore sinkrono eta asinkronoak harrapatu eta middlewarera desbideratzen ditugu hemen
|
||||
try {
|
||||
bezeroZerbitzua.gehituBerria(req.body).then((emaitza) => {
|
||||
res.status(200).json(emaitza);
|
||||
}).catch((errorea) => {
|
||||
next(errorea)
|
||||
});
|
||||
}
|
||||
catch (errorea) {
|
||||
next(errorea);
|
||||
}
|
||||
|
||||
// Errore-kudeaketa middlewarea, errore kudeatzaile zentralizatuari uzten diogu errore kudeaketa
|
||||
app.use(async (errorea, req, res, next) => {
|
||||
const operazioErroreaDa = await erroreKudeatzailea.kudeatuErrorea(errorea);
|
||||
if (!operazioErroreaDa) {
|
||||
next(errorea);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
// DAL (Data Access Layer) geruza, ez ditugu erroreak hemen kudeatzen
|
||||
DB.gehituDokumentua(bezeroBerria, (errorea: Error, emaitza: Result) => {
|
||||
if (errorea)
|
||||
throw new Error('Errore azalpen bikaina dator hemen', bestelako parametro erabilgarri batzuk)
|
||||
});
|
||||
|
||||
// API bide kodea, errore sinkrono eta asinkronoak harrapatu eta middlewarera desbideratzen ditugu hemen
|
||||
try {
|
||||
bezeroZerbitzua.gehituBerria(req.body).then((emaitza: Result) => {
|
||||
res.status(200).json(emaitza);
|
||||
}).catch((errorea: Error) => {
|
||||
next(errorea)
|
||||
});
|
||||
}
|
||||
catch (errorea) {
|
||||
next(errorea);
|
||||
}
|
||||
|
||||
// Errore-kudeaketa middlewarea, errore kudeatzaile zentralizatuari uzten diogu errore kudeaketa
|
||||
app.use(async (errorea: Error, req: Request, res: Response, next: NextFunction) => {
|
||||
const operazioErroreaDa = await erroreKudeatzailea.kudeatuErrorea(errorea);
|
||||
if (!operazioErroreaDa) {
|
||||
next(errorea);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Kode adibidea: erroreen kudeaketa ardura bakarreko objektuekin
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
module.exports.kudeatzailea = new erroreKudeatzailea();
|
||||
|
||||
function erroreKudeatzailea() {
|
||||
this.erroreaKudeatu = async (errorea) => {
|
||||
await logger.erroreaErregistratu(errorea);
|
||||
await kritikoaBadaAdministrariariPostaElektronikoaBidali;
|
||||
await kritikoaBadaOperazioZerrendanGorde;
|
||||
await erabakiIaOperazioErroreaDen;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
class ErroreKudeatzailea {
|
||||
public async erroreaKudeatu(errorea: Error): Promise<void> {
|
||||
await logger.erroreaErregistratu(errorea);
|
||||
await kritikoaBadaAdministrariariPostaElektronikoaBidali();
|
||||
await kritikoaBadaOperazioZerrendanGorde();
|
||||
await erabakiIaOperazioErroreaDen();
|
||||
}
|
||||
}
|
||||
|
||||
export const kudeatzailea = new ErroreKudeatzailea();
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Anti ereduaren kode adibidea: kudeatu erroreak middleware barruan
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
// zuzeneko errore kudeaketa middlewarean, Cron atazak eta frogatze erroreak kudeatuko dituena?
|
||||
app.use((errorea, req, res, next) => {
|
||||
logger.erroreaErregistratu(errorea);
|
||||
if (errorea.larritasuna == erroreak.altua) {
|
||||
posta.postaElektronikoaBidali(
|
||||
konfigurazioa.administrariPostaElektronikoa,
|
||||
"Errore kritikoa gertatu da",
|
||||
errorea
|
||||
);
|
||||
}
|
||||
if (!errorea.operazioErroreaDa) {
|
||||
next(errorea);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
// zuzeneko errore kudeaketa middlewarean, Cron atazak eta frogatze erroreak kudeatuko dituena?
|
||||
app.use((errorea: Error, req: Request, res: Response, next: NextFunction) => {
|
||||
logger.erroreaErregistratu(errorea);
|
||||
if (errorea.larritasuna == erroreak.altua) {
|
||||
posta.postaElektronikoaBidali(
|
||||
konfigurazioa.administrariPostaElektronikoa,
|
||||
"Errore kritikoa gertatu da",
|
||||
errorea
|
||||
);
|
||||
}
|
||||
if (!errorea.operazioErroreaDa) {
|
||||
next(errorea);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Blogeko aipua: "Batzuetan maila baxuagoek beren deitzaileari errorea bidaltzea baino ezer praktikoagorik ezin dute egin"
|
||||
|
||||
Joyent blogeko “Node.js errore kudeaketa" hitz gako bati esker sailkatua
|
||||
|
||||
> …Errore bera pilaren maila askotan kudeatzen bukatuko duzu. Hau gertatzen da maila baxuenek beren deitzaileei (eta beste haiek beren deitzaileei, etab.) errorea bidaltzea baino beste ezer egokiagorik ezin dutenean egin. Askotan, soilik goi mailako deitzaileak daki zein den erantzun zuzena, ia ahalegin operazio berria den, erabiltzaileari errorearen berri eman behar dion, edo beste edozer. Baina horrek ez du esan nahi errore guztiak goi mailako callback bakar bati jakinarazi behar dizkiozunik, callback horrek ere errorea zein testuingurutan gertatu den ez daki eta…
|
||||
|
||||
### Blogeko aipua: "Errore bakoitza bakarka kudeatzea bikoizte galanta izan daiteke"
|
||||
|
||||
JS Recipes blogeko “Node.js errore kudeaketa" 17 hitz gakori esker sailkatua
|
||||
|
||||
> ……Hackathoneko Starter api.js kontrolatzaile bakarrean, 79 errore objektu inguru daude. Errore bakoitza bakarka kudeatzeak kodea ikaragarri bikoiztea eragin dezake. Hurrengo egin dezakezun gauza hoberena da errore kudeaketa logika Express middleware bati uztea…
|
||||
|
||||
### Blogeko aipua: "HTTP erroreak ezin dira zure datu basearen kodean egon"
|
||||
|
||||
Daily JS blogeko “Node.js errore kudeaketa" 14 hitz gakori esker sailkatua
|
||||
|
||||
> ……Errore objektuetan ezaugarri erabilgarriak zehaztu beharko zenituzke, baina ezaugarri horiek tinko erabiliz. Eta, ez gurutzatu korronteak: HTTP erroreak ezin dira zure datu basearen kodean egon. Edota, nabigatzaile garatzaileentzat, Ajax erroreak zerbitzariarekin hitz egiten duten kodean egon daitezke, baina Mustache txantiloiak prozesatzen dituen koderik ez…
|
||||
@ -1,10 +1,10 @@
|
||||
# Handle errors centrally. Not within middlewares
|
||||
# 에러를 미들웨어에서 처리하지 말고 한군데에서 집중적으로 처리해라
|
||||
|
||||
### One Paragraph Explainer
|
||||
### 한문단 설명
|
||||
|
||||
Without one dedicated object for error handling, greater are the chances of important errors hiding under the radar due to improper handling. The error handler object is responsible for making the error visible, for example by writing to a well-formatted logger, sending events to some monitoring product like [Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/), or [Raygun](https://raygun.com/). Most web frameworks, like [Express](http://expressjs.com/en/guide/error-handling.html#writing-error-handlers), provide an error handling middleware mechanism. A typical error handling flow might be: Some module throws an error -> API router catches the error -> it propagates the error to the middleware (e.g. Express, KOA) who is responsible for catching errors -> a centralized error handler is called -> the middleware is being told whether this error is an untrusted error (not operational) so it can restart the app gracefully. Note that it’s a common, yet wrong, practice to handle errors within Express middleware – doing so will not cover errors that are thrown in non-web interfaces.
|
||||
에러 처리를 위한 전용 객체가 없으면 잘못된 처리로 인해 중요한 에러가 숨어있을 가능성이 더 커진다. 예를 들어, 에러 처리 객체는 [Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/), 또는 [Raygun](https://raygun.com/))와 같은 모니터링 프로그램에 이벤트를 보내 에러를 가시적으로 만드는 역할을 한다. [Express](http://expressjs.com/en/guide/error-handling.html#writing-error-handlers),와 같은 대부분의 웹 프레임워크는 미들웨어 메커니즘 에러처리를 제공한다. 일반적인 에러 처리 흐름은 다음과 같다: 일부 모듈이 에러를 던진다 -> API 라우터가 에러를 잡는다 -> 에러를 에러 검출을 담당하는 미들웨어(예: Express, KOA)에 전달한다 -> 중앙 에러 처리기가 호출된다 -> 미들웨어는 이 에러가 신뢰할 수 없는 에러인지(작동하지 않음) 알려 앱을 정상적으로 재시작 할 수 있다. Express 미들웨어 내에서 오류를 처리하는 것이 일반적이지만 잘못된 관습이다 – 이렇게 하면 웹 이외의 인터페이스에 발생하는 에러를 해결 할 수 없다.
|
||||
|
||||
### Code Example – a typical error flow
|
||||
### 코드 예시 – 일반적인 에러 흐름
|
||||
|
||||
```javascript
|
||||
// DAL layer, we don't handle errors here
|
||||
@ -34,7 +34,7 @@ app.use(async (err, req, res, next) => {
|
||||
});
|
||||
```
|
||||
|
||||
### Code example – handling errors within a dedicated object
|
||||
### 코드 예시 – 전용 객체에서 에러 처리
|
||||
|
||||
```javascript
|
||||
module.exports.handler = new errorHandler();
|
||||
@ -49,7 +49,7 @@ function errorHandler() {
|
||||
}
|
||||
```
|
||||
|
||||
### Code Example – Anti Pattern: handling errors within the middleware
|
||||
### 코드 예시 – 좋지않은 패턴: 미들웨어에서 에러 처리
|
||||
|
||||
```javascript
|
||||
// middleware handling the error directly, who will handle Cron jobs and testing errors?
|
||||
@ -64,20 +64,20 @@ app.use((err, req, res, next) => {
|
||||
});
|
||||
```
|
||||
|
||||
### Blog Quote: "Sometimes lower levels can’t do anything useful except propagate the error to their caller"
|
||||
### 블로그 인용: "때로 하위 레벨은 호출자에게 전달하는 것 외에 쓸모있는 일을 할 수 없다"
|
||||
|
||||
From the blog Joyent, ranked 1 for the keywords “Node.js error handling”
|
||||
Joyent 블로그에서 "Node.js 에러 처리" 키워드 1위에 위치했다
|
||||
|
||||
> …You may end up handling the same error at several levels of the stack. This happens when lower levels can’t do anything useful except propagate the error to their caller, which propagates the error to its caller, and so on. Often, only the top-level caller knows what the appropriate response is, whether that’s to retry the operation, report an error to the user, or something else. But that doesn’t mean you should try to report all errors to a single top-level callback, because that callback itself can’t know in what context the error occurred…
|
||||
> …스택의 여러 레벨에서 동일한 오류를 처리할 수 있다. 이는 하위 레벨 수준에서 에러를 호출자에게 전달하는 것 외에는 쓸모있는 작업을 수행 할 수 없을 때 발생한다. 종종, 최상위 레벨 호출자만이 적절한 응답, 작업을 재시도할지, 사용자에게 에러를 보고할지, 또는 다른 작업을 수행할지를 알 수 있다. 그러나 모든 에러를 최상위 레벨에 보고해야 한다는 의미는 아니다, 왜냐하면 콜백 자체는 어떤 맥락에서 에러가 발생했는지 알 수 없기 때문이다…
|
||||
|
||||
### Blog Quote: "Handling each err individually would result in tremendous duplication"
|
||||
### 블로그 인용: "각 에러를 개별적으로 처리하면 엄청난 중복이 발생할 수 있다"
|
||||
|
||||
From the blog JS Recipes ranked 17 for the keywords “Node.js error handling”
|
||||
JS Recipes 블로그에서 "Node.js 에러 처리" 키워드 17위에 위치했다
|
||||
|
||||
> ……In Hackathon Starter api.js controller alone, there are over 79 occurrences of error objects. Handling each err individually would result in a tremendous amount of code duplication. The next best thing you can do is to delegate all error handling logic to an Express middleware…
|
||||
> ……Hackathon Starter api.js 컨트롤러에서만 79개 이상의 오류 객체가 있다. 각 에러를 개별적으로 처리하면 엄청난 중복이 발생할 수 있다. 다음으로 가장 좋은 방법은 모든 에러 처리 로직을 Express 미들웨어에 위임하는 것이다…
|
||||
|
||||
### Blog Quote: "HTTP errors have no place in your database code"
|
||||
### 블로그 인용: "HTTP 에러는 데이터베이스 코드에 포함되지 않는다"
|
||||
|
||||
From the blog Daily JS ranked 14 for the keywords “Node.js error handling”
|
||||
Daily JS 블로그에서 "Node.js 에러 처리" 키워드 14위에 위치했다
|
||||
|
||||
> ……You should set useful properties in error objects, but use such properties consistently. And, don’t cross the streams: HTTP errors have no place in your database code. Or for browser developers, Ajax errors have a place in the code that talks to the server, but not code that processes Mustache templates…
|
||||
> ……에러 객체에 유용한 속성을 설정해야 하지만, 이런 속성은 일관되게 사용해야 한다. 그리고, 스트림을 넘지 마라: HTTP 에러는 데이터베이스 코드에 포함되지 않는다. 또한 브라우저 개발자의 경우, Ajax 에러는 서버와 통신하는 코드가 있지만, 머스테치(Mustache) 템플릿을 처리하는 코드는 아니다…
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
### One Paragraph Explainer
|
||||
|
||||
Without one dedicated object for error handling, greater are the chances of important errors hiding under the radar due to improper handling. The error handler object is responsible for making the error visible, for example by writing to a well-formatted logger, sending events to some monitoring product like [Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/), or [Raygun](https://raygun.com/). Most web frameworks, like [Express](http://expressjs.com/en/guide/error-handling.html#writing-error-handlers), provide an error handling middleware mechanism. A typical error handling flow might be: Some module throws an error -> API router catches the error -> it propagates the error to the middleware (e.g. Express, KOA) who is responsible for catching errors -> a centralized error handler is called -> the middleware is being told whether this error is an untrusted error (not operational) so it can restart the app gracefully. Note that it’s a common, yet wrong, practice to handle errors within Express middleware – doing so will not cover errors that are thrown in non-web interfaces.
|
||||
Without one dedicated object for error handling, greater are the chances for inconsistent errors handling: Errors thrown within web requests might get handled differently from those raised during the startup phase and those raised by scheduled jobs. This might lead to some types of errors that are being mismanaged. This single error handler object is responsible for making the error visible, for example, by writing to a well-formatted logger, firing metrics using some monitoring product (like [Prometheus](https://prometheus.io/), [CloudWatch](https://aws.amazon.com/cloudwatch/), [DataDog](https://www.datadoghq.com/), and [Sentry](https://sentry.io/)) and to decide whether the process should crash. Most web frameworks provide an error catching middleware mechanism - A typical mistake is to place the error handling code within this middleware. By doing so, you won't be able to reuse the same handler for errors that are caught in different scenarios like scheduled jobs, message queue subscribers, and uncaught exceptions. Consequently, the error middleware should only catch errors and forward them to the handler. A typical error handling flow might be: Some module throws an error -> API router catches the error -> it propagates the error to the middleware (e.g. or to other mechanism for catching request-level error) who is responsible for catching errors -> a centralized error handler is called.
|
||||
|
||||
### Code Example – a typical error flow
|
||||
|
||||
@ -30,11 +30,16 @@ catch (error) {
|
||||
|
||||
// Error handling middleware, we delegate the handling to the centralized error handler
|
||||
app.use(async (err, req, res, next) => {
|
||||
const isOperationalError = await errorHandler.handleError(err);
|
||||
if (!isOperationalError) {
|
||||
next(err);
|
||||
}
|
||||
await errorHandler.handleError(err, res);//The error handler will send a response
|
||||
});
|
||||
|
||||
process.on("uncaughtException", error => {
|
||||
errorHandler.handleError(error);
|
||||
});
|
||||
|
||||
process.on("unhandledRejection", (reason) => {
|
||||
errorHandler.handleError(reason);
|
||||
});
|
||||
```
|
||||
</details>
|
||||
|
||||
@ -62,11 +67,16 @@ catch (error) {
|
||||
|
||||
// Error handling middleware, we delegate the handling to the centralized error handler
|
||||
app.use(async (err: Error, req: Request, res: Response, next: NextFunction) => {
|
||||
const isOperationalError = await errorHandler.handleError(err);
|
||||
if (!isOperationalError) {
|
||||
next(err);
|
||||
}
|
||||
await errorHandler.handleError(err, res);
|
||||
});
|
||||
|
||||
process.on("uncaughtException", (error:Error) => {
|
||||
errorHandler.handleError(error);
|
||||
});
|
||||
|
||||
process.on("unhandledRejection", (reason) => {
|
||||
errorHandler.handleError(reason);
|
||||
});
|
||||
```
|
||||
</details>
|
||||
|
||||
@ -80,11 +90,10 @@ app.use(async (err: Error, req: Request, res: Response, next: NextFunction) => {
|
||||
module.exports.handler = new errorHandler();
|
||||
|
||||
function errorHandler() {
|
||||
this.handleError = async (err) => {
|
||||
await logger.logError(err);
|
||||
await sendMailToAdminIfCritical;
|
||||
await saveInOpsQueueIfCritical;
|
||||
await determineIfOperationalError;
|
||||
this.handleError = async (error, responseStream) => {
|
||||
await logger.logError(error);
|
||||
await fireMonitoringMetric(error);
|
||||
await crashIfUntrustedErrorOrSendResponse(error, responseStream);
|
||||
};
|
||||
}
|
||||
```
|
||||
@ -95,12 +104,11 @@ function errorHandler() {
|
||||
|
||||
```typescript
|
||||
class ErrorHandler {
|
||||
public async handleError(err: Error): Promise<void> {
|
||||
await logger.logError(err);
|
||||
await sendMailToAdminIfCritical();
|
||||
await saveInOpsQueueIfCritical();
|
||||
await determineIfOperationalError();
|
||||
};
|
||||
public async handleError(err: Error, responseStream: Response): Promise<void> {
|
||||
await logger.logError(error);
|
||||
await fireMonitoringMetric(error);
|
||||
await crashIfUntrustedErrorOrSendResponse(error, responseStream);
|
||||
};
|
||||
}
|
||||
|
||||
export const handler = new ErrorHandler();
|
||||
@ -145,6 +153,10 @@ app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
|
||||
```
|
||||
</details>
|
||||
|
||||
### Illustration: The error handling actors and flow
|
||||

|
||||
|
||||
|
||||
### Blog Quote: "Sometimes lower levels can’t do anything useful except propagate the error to their caller"
|
||||
|
||||
From the blog Joyent, ranked 1 for the keywords “Node.js error handling”
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
### Объяснение в один абзац
|
||||
|
||||
Без специального выделенного объекта для обработки ошибок больше шансов на то, что важные ошибки скрываются под радаром из-за неправильного обращения. Объект обработчика ошибок отвечает за отображение ошибки, например, путем записи в хорошо отформатированный регистратор, отправки событий в некоторые продукты мониторинга, такие как [Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/) или [Raygun](https://raygun.com/). Большинство веб-фреймворков, таких как [Express](http://expressjs.com/en/guide/error-handling.html#writing-error-handlers), предоставляют механизм промежуточного программного обеспечения для обработки ошибок. Типичный поток обработки ошибок может быть следующим: какой-то модуль выдает ошибку -> маршрутизатор API перехватывает ошибку -> он передает ошибку промежуточному программному обеспечению (например, Express, KOA), которое отвечает за перехват ошибок -> вызывается централизованный обработчик ошибок -> промежуточному программному обеспечению сообщается, является ли эта ошибка ненадежной (не работающей), чтобы она могла корректно перезапустить приложение. Обратите внимание, что обычная, но неправильная практика - обрабатывать ошибки в промежуточном программном обеспечении Express - это не распространяется на ошибки, возникающие в не-веб-интерфейсах.
|
||||
Без выделенного объекта для обработки ошибок есть больше шансов на то, что ошибки потеряются с радара из-за их неправильной обработки. Объект обработчика ошибок отвечает за отображение ошибки, например, путем записи в логгер, отправки событий в сервисы мониторинга, такие как [Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/) или [Raygun](https://raygun.com/). Большинство веб-фреймворков, таких как [Express](http://expressjs.com/en/guide/error-handling.html#writing-error-handlers), предоставляют механизм обработки ошибок с помощью функций промежуточной обработки (**middlewares**). Типичный поток обработки ошибок может выглядеть следующим образом: какой-то модуль выдает ошибку -> API-маршрутизатор перехватывает ошибку -> он передает ошибку функции промежуточной обработки (Express, KOA), которая отвечает за перехват ошибок -> вызывается централизованный обработчик ошибок -> функции промежуточной обработки передается информация о том, что является ли эта ошибка ненадежной (необрабатываемой), чтобы она могла корректно перезапустить приложение. Обратите внимание, что обычная, но неправильная практика - обрабатывать ошибки в функции промежуточной обработки Express - это не распространяется на ошибки, возникающие в не-веб-интерфейсах.
|
||||
|
||||
### Пример кода - типичный поток ошибок
|
||||
|
||||
@ -10,13 +10,14 @@
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
// DAL layer, we don't handle errors here
|
||||
// DAL-слой, мы не обрабатываем ошибки тут
|
||||
DB.addDocument(newCustomer, (error, result) => {
|
||||
if (error)
|
||||
throw new Error('Great error explanation comes here', other useful parameters)
|
||||
});
|
||||
|
||||
// API route code, we catch both sync and async errors and forward to the middleware
|
||||
// код API-маршрутизатора, мы обрабатываем как sync
|
||||
// так и async ошибки и переходим к middleware
|
||||
try {
|
||||
customerService.addNew(req.body).then((result) => {
|
||||
res.status(200).json(result);
|
||||
@ -28,7 +29,7 @@ catch (error) {
|
||||
next(error);
|
||||
}
|
||||
|
||||
// Error handling middleware, we delegate the handling to the centralized error handler
|
||||
// Обработка ошибок в middleware, мы делегируем обработку централизованному обработчику ошибок
|
||||
app.use(async (err, req, res, next) => {
|
||||
const isOperationalError = await errorHandler.handleError(err);
|
||||
if (!isOperationalError) {
|
||||
@ -42,13 +43,14 @@ app.use(async (err, req, res, next) => {
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
// DAL layer, we don't handle errors here
|
||||
// DAL-слой, мы не обрабатываем ошибки тут
|
||||
DB.addDocument(newCustomer, (error: Error, result: Result) => {
|
||||
if (error)
|
||||
throw new Error('Great error explanation comes here', other useful parameters)
|
||||
});
|
||||
|
||||
// API route code, we catch both sync and async errors and forward to the middleware
|
||||
// код API-маршрутизатора, мы обрабатываем как sync
|
||||
// так и async ошибки и переходим к middleware
|
||||
try {
|
||||
customerService.addNew(req.body).then((result: Result) => {
|
||||
res.status(200).json(result);
|
||||
@ -60,7 +62,7 @@ catch (error) {
|
||||
next(error);
|
||||
}
|
||||
|
||||
// Error handling middleware, we delegate the handling to the centralized error handler
|
||||
// Обработка ошибок в middleware, мы делегируем обработку централизованному обработчику ошибок
|
||||
app.use(async (err: Error, req: Request, res: Response, next: NextFunction) => {
|
||||
const isOperationalError = await errorHandler.handleError(err);
|
||||
if (!isOperationalError) {
|
||||
@ -82,9 +84,9 @@ module.exports.handler = new errorHandler();
|
||||
function errorHandler() {
|
||||
this.handleError = async (err) {
|
||||
await logger.logError(err);
|
||||
await sendMailToAdminIfCritical;
|
||||
await saveInOpsQueueIfCritical;
|
||||
await determineIfOperationalError;
|
||||
await sendMailToAdminIfCritical(err);
|
||||
await saveInOpsQueueIfCritical(err);
|
||||
await determineIfOperationalError(err);
|
||||
};
|
||||
}
|
||||
```
|
||||
@ -97,9 +99,9 @@ function errorHandler() {
|
||||
class ErrorHandler {
|
||||
public async handleError(err: Error): Promise<void> {
|
||||
await logger.logError(err);
|
||||
await sendMailToAdminIfCritical();
|
||||
await saveInOpsQueueIfCritical();
|
||||
await determineIfOperationalError();
|
||||
await sendMailToAdminIfCritical(err);
|
||||
await saveInOpsQueueIfCritical(err);
|
||||
await determineIfOperationalError(err);
|
||||
};
|
||||
}
|
||||
|
||||
@ -108,13 +110,14 @@ export const handler = new ErrorHandler();
|
||||
</details>
|
||||
|
||||
|
||||
### Пример кода - антипаттерн: обработка ошибок в промежуточном программном обеспечении
|
||||
### Пример кода - антипаттерн: обработка ошибок в middleware
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
// middleware handling the error directly, who will handle Cron jobs and testing errors?
|
||||
// middleware, обрабатывающий ошибки напрямую.
|
||||
// А кто будет обрабатывать ошибки возникшие в Cron или при юнит-тестировании?
|
||||
app.use((err, req, res, next) => {
|
||||
logger.logError(err);
|
||||
if (err.severity == errors.high) {
|
||||
@ -132,7 +135,8 @@ app.use((err, req, res, next) => {
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
// middleware handling the error directly, who will handle Cron jobs and testing errors?
|
||||
// middleware, обрабатывающий ошибки напрямую.
|
||||
// А кто будет обрабатывать ошибки возникшие в Cron или при юнит-тестировании?
|
||||
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
|
||||
logger.logError(err);
|
||||
if (err.severity == errors.high) {
|
||||
@ -145,20 +149,20 @@ app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
|
||||
```
|
||||
</details>
|
||||
|
||||
### Цитата из блога: "Иногда нижние уровни не могут сделать ничего полезного, кроме как сообщить об ошибке вызывающей стороне"
|
||||
### Цитата из блога: "Иногда нижние слои не могут сделать ничего полезного, кроме как сообщить об ошибке вызывающему слою"
|
||||
|
||||
Из блога Joyent, занимающий 1 место по ключевым словам "Обработка ошибок Node.js"
|
||||
Из блога Joyent, занимающего 1 место по ключевым словам "Обработка ошибок Node.js"
|
||||
|
||||
> … Вы можете обработать одну и ту же ошибку на нескольких уровнях стека. Это происходит, когда нижние уровни не могут сделать ничего полезного, кроме как передать ошибку вызывающей стороне, которая передает ошибку своей вызывающей стороне, и так далее. Зачастую только вызывающий пользователь верхнего уровня знает, что является подходящим ответом: попытка повторить операцию, сообщить пользователю об ошибке или что-то еще. Но это не значит, что вы должны пытаться сообщать обо всех ошибках в один обратный вызов верхнего уровня, потому что сам этот обратный вызов не может знать, в каком контексте произошла ошибка …
|
||||
> … Вы можете обработать одну и ту же ошибку на нескольких слоях. Это происходит, когда нижние слои не могут сделать ничего полезного, кроме как передать ошибку вызывающему слою, который передаст ошибку своему вызывающему слою, и так далее. Зачастую только самый верхний слой знает, что является подходящим действием на ошибку: попытка повторить операцию, сообщить пользователю об ошибке или что-то еще. Но это не значит, что вы должны пытаться сообщать обо всех ошибках в один верхний callback, потому что этот callback не может знать, в каком контексте произошла ошибка …
|
||||
|
||||
### Цитата из блога: "Обработка каждой ошибки по отдельности приведет к огромному дублированию"
|
||||
### Цитата из блога: "Обработка каждой ошибки по отдельности приведет к ужасному дублированию"
|
||||
|
||||
Из блога JS Recipes, занимающий 17 место по ключевым словам "Обработка ошибок Node.js"
|
||||
Из блога JS Recipes, занимающего 17 место по ключевым словам "Обработка ошибок Node.js"
|
||||
|
||||
> … Только в контроллере api.js Hackathon Starter имеется более 79 случаев появления объектов ошибок. Обработка каждой ошибки в отдельности привела бы к огромному количеству дублирования кода. Следующее, что вы можете сделать, это делегировать всю логику обработки ошибок в промежуточное ПО Express …
|
||||
> … Только в контроллере api.js Hackathon Starter имеется более 79 объектов ошибок. Обработка каждой ошибки в отдельности привела бы к ужасному дублированию кода. Следующее, что вы можете сделать, это делегировать всю логику обработки ошибок в middleware Express …
|
||||
|
||||
### Цитата из блога: "В коде вашей базы данных нет места ошибкам HTTP"
|
||||
|
||||
Из блога Daily JS, занимающем 14 место по ключевым словам "Обработка ошибок Node.js"
|
||||
|
||||
> … Вы должны установить полезные свойства в объектах ошибок, но использовать их последовательно. И не пересекайте потоки: в коде вашей базы данных нет места ошибкам HTTP. Или для разработчиков браузеров, ошибки Ajax имеют место в коде, который общается с сервером, но не в коде, который обрабатывает шаблоны усов …
|
||||
> … Вы должны добавлять полезные свойства в объекты ошибок, но использовать их согласовано. И не пересекайте логику: в коде вашей базы данных нет места ошибкам HTTP. Или, например, для frontend-разработчиков, ошибки Ajax имеют место в коде, который общается с сервером, но не в коде, который работает с шаблонами Mustache …
|
||||
|
||||
53
sections/errorhandling/documentingusingswagger.basque.md
Normal file
53
sections/errorhandling/documentingusingswagger.basque.md
Normal file
@ -0,0 +1,53 @@
|
||||
# Dokumentatu API erroreak OpenAPI (aurretik Swagger bezala ezagutua) edo GraphQL-ren laguntzarekin
|
||||
|
||||
### Azalpen paragrafoa
|
||||
|
||||
REST APIek HTTP estatus kodigoak erabiliz bueltatzen dituzte emaitzak. APIaren erabiltzailearentzat guztiz beharrezkoa da APIaren egituraren eta baita ere errore posibleen berri izatea, erabiltzaileak errorea atzeman eta kontu handiz kudea dezake eta. Adibidez, zure APIaren dokumentazioak aurrez azaldu behar du 409 HTTP estatus kodea bueltatzen dela bezeroaren izena iada existitzen denean (APIak bezero berriak gordetzen dituela ziurtzat joz), APIaren erabiltzaileak egoera bakoitzerako bistaratze egokiena proposa dezan. OpenAPI (aintzina Swagger) APIaren dokumentaziorako eskema bat zehazten duen estandar bat da, dokumentazioa online modu errazean sortzea ahalbidetzen duten tresna ekosistema bat proposatuz. Begiratu hurrengo pantailako argazkiak beherago
|
||||
|
||||
Dagoeneko GraphQL erabiltzen baduzu zure APIaren helburuetarako, zure eskemak iada zorrozki bermatzen du zein errorek zein itxura eduki beharko luketen ([dokumentuan laburbilduta](https://facebook.github.io/graphql/June2018/#sec-Errors)) eta nola kudeatu beharko liratekeen zure bezero tresnekin Gainera, komentarioz osatutako dokumentazioa ere gehi zenezake.
|
||||
|
||||
|
||||
### GraphQL errore baten adibidea
|
||||
|
||||
> Adibide honek [SWAPI](https://graphql.org/swapi-graphql) erabiltzen du, Star Warsen APIa.
|
||||
|
||||
```graphql
|
||||
# huts egin beharko luke id ez baita zuzena
|
||||
{
|
||||
filmea(id: "1ZmlsbXM6MQ==") {
|
||||
izenburua
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"erroreak": [
|
||||
{
|
||||
"mezua": "Ez dago sarrerarik cache lokalean https://swapi.co/api/films/.../-rentzat",
|
||||
"lekuak": [
|
||||
{
|
||||
"ilara": 2,
|
||||
"zutabea": 3
|
||||
}
|
||||
],
|
||||
"bidea": [
|
||||
"filmea"
|
||||
]
|
||||
}
|
||||
],
|
||||
"datuak": {
|
||||
"filmea": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Blogeko aipua: "Zure deitzaileei zein errore gertatu diren esan behar diezu"
|
||||
|
||||
Joyent blogeko “Node.js erregistratzea“ hitz gako bati esker sailkatua
|
||||
|
||||
> Erroreak nola kudeatu behar diren aztertu dugu, baina funtzio berri bat idazten ari zarenean, nola bidaltzen dizkiozu erroreak zure funtzioa deitu duen kodeari? …Zein errore gerta litezkeen edo haiekk zer esan nahi duten ez badakizu, esan nahi du zure programa ezin litekeela zuzena izan, txiripaz izan ezean. Beraz, funtzio berri bat idazten ari bazara, zure deitzailei zein errore gerta litezkeen eta haiek zer esan nahi duten esan behar diezu…
|
||||
|
||||
### Tresna erabilgarria: Swagger Online Dokumentazio Sortzailea
|
||||
|
||||

|
||||
@ -1,8 +1,8 @@
|
||||
# Document API errors using Swagger or GraphQL
|
||||
# Document API errors using OpenAPI Specification (earlier known as Swagger) or GraphQL
|
||||
|
||||
### One Paragraph Explainer
|
||||
|
||||
REST APIs return results using HTTP status codes, it’s absolutely required for the API user to be aware not only about the API schema but also about potential errors – the caller may then catch an error and tactfully handle it. For example, your API documentation might state in advance that HTTP status 409 is returned when the customer name already exists (assuming the API register new users) so the caller can correspondingly render the best UX for the given situation. Swagger is a standard that defines the schema of API documentation offering an eco-system of tools that allow creating documentation easily online, see print screens below
|
||||
REST APIs return results using HTTP status codes, it’s absolutely required for the API user to be aware not only about the API schema but also about potential errors – the caller may then catch an error and tactfully handle it. For example, your API documentation might state in advance that HTTP status 409 is returned when the customer name already exists (assuming the API register new users) so the caller can correspondingly render the best UX for the given situation. OpenAPI (eka Swagger) is a standard that defines the schema of API documentation offering an eco-system of tools that allow creating documentation easily online, see print screens below
|
||||
|
||||
If you have already adopted GraphQL for your API endpoints, your schema already contains strict guarantees as to what errors should look like ([outlined in the spec](https://facebook.github.io/graphql/June2018/#sec-Errors)) and how they should be handled by your client-side tooling. In addition, you can also supplement them with comment-based documentation.
|
||||
|
||||
|
||||
71
sections/errorhandling/failfast.basque.md
Normal file
71
sections/errorhandling/failfast.basque.md
Normal file
@ -0,0 +1,71 @@
|
||||
# Huts egin azkar, balidatu argudioak liburutegi dedikatu baten laguntzarekin
|
||||
|
||||
### Azalpen paragrafoa
|
||||
|
||||
Denok dakigu argudioak egiaztatzea eta azkar huts egitea garrantzitsua dela ezkutuko erroreak ekiditeko (ikusi ereduaren aurkako kodearen adibidea behean). Bestela, irakurri zerbait programazio esplizituaren eta babes programazioaren gainean. Errealitatean, hori ekiditeko ohitura daukagu, kodea idazteak suposatzen duen gogaikarritasuna dela eta (adibidez pentsatu posta elektronikoa eta datak bezalako alorrak dituen JSON objektu hierarkiko bat balioztatzea). Joi eta Validator bezalako liburutegiek asko leuntzen dute lan hori.
|
||||
|
||||
### Wikipedia: programazio defentsiboa
|
||||
|
||||
Programazio defentsiboa softwarea eta iturburu kodea hobetzeko ikuspuntua da, kalitate orokorrari dagokionez, software errore eta arazo kopurua murriztuz. Iturburu kodea ulergarria izango bada, irakurgarria eta ulergarria izan behar da kode auditoria batean onartua izan dadin. Softwarea aurreikusteko moduko eran jokatzeko egin behar da, ustekabeko sarrerak edo erabiltzaile ekintzak gertatu arren.
|
||||
|
||||
### Kode adibidea: balioztatu JSON sarrera koplexua ‘Joi’ erabiliz
|
||||
|
||||
```javascript
|
||||
var kideEskema = Joi.object().keys({
|
||||
pasahitza: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),
|
||||
jaioteguna: Joi.number().integer().min(1900).max(2013),
|
||||
postaElektronikoa: Joi.string().email(),
|
||||
});
|
||||
|
||||
function kideBerriaGehitu(kideBerria) {
|
||||
// lehenengo baieztapena dator
|
||||
Joi.assert(kideBerria, kideEskema); //jaurti balioztatzeak huts egiten badu
|
||||
// bestelako logika hemen
|
||||
}
|
||||
```
|
||||
|
||||
### Anti eredua: balioztatze ezak errore kaskarrak dakartza
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
// deskontua positiboa bada, bidali erabiltzailea bere deskontu tiketak inprimatzera
|
||||
function bidaliDeskontuTiketakInprimatzera(httpResponse, kidea, deskontua) {
|
||||
if (deskontua != 0) {
|
||||
httpResponse.redirect(`/deskontuInpresioBistaratzea/${kidea.id}`);
|
||||
}
|
||||
}
|
||||
|
||||
bidaliDeskontuTiketakInprimatzera(httpResponse, kiderenBat);
|
||||
// deskontu parametroa pasatzea ahaztuta, orduan zergatik bidali da erabiltzailea deskontu pantailara?
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
// deskontua positiboa bada bidali erabiltzailea bere deskontu tiketak inprimatzera
|
||||
function bidaliDeskontuTiketakInprimatzera(
|
||||
httpResponse: Response,
|
||||
kidea: Member,
|
||||
deskontua: number
|
||||
) {
|
||||
if (deskontua != 0) {
|
||||
httpResponse.redirect(`/deskontuInpresioBistaratzea/${kidea.id}`);
|
||||
}
|
||||
}
|
||||
|
||||
bidaliDeskontuTiketakInprimatzera(httpResponse, kiderenBat, -12);
|
||||
// deskontu parametro negatiboa pasatu dugu, We passed a negative parameter discount, orduan zergatik bidali da erabiltzailea deskontu pantailara?
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Blogeko aipua: "Errore hauek zuzenean jaurti beharko zenituzke"
|
||||
|
||||
Joyent blogetik hartua
|
||||
|
||||
> Kasu degeneratu bat da norbaitek funtzio asinkrono bat callback gabe deitzea atzera deirik egin gabe. Errore horiek berehala jaurti beharko zenituzke programa apurtuta baitago eta hori arazteak gutxienez pila arrastoa eta errorearen lekuko fitxategia berreskuratzea eskatzen du. Hori egiteko, funtzioaren hasieran argudio guztien motak balioztatzea gomendatzen dugu.
|
||||
100
sections/errorhandling/operationalvsprogrammererror.basque.md
Normal file
100
sections/errorhandling/operationalvsprogrammererror.basque.md
Normal file
@ -0,0 +1,100 @@
|
||||
# Bereizi eragiketa erroreak eta programazio erroreak
|
||||
|
||||
### Azalpen paragrafoa
|
||||
|
||||
Ondorengo bi errore mota hauek bereizteak zure aplikazioaren matxura denbora gutxitu eta programazio errore eroak ekiditen lagunduko dizu. Batetik, eragiketa erroreak daude, gertatutako arazoa eta haren ondorioak ulertzen dituzunean (adibidez, HTTP zerbitzu bati egindako deiak huts egitea, konexio arazoak direla eta. Bestetik, errorea zergatik eta nondik etorri den ez dakizun egoerei programatze errore deritze (balio zehaztugabe bat irakurtzen saiatzen den kodea edo memoria ihes egiten dion datu basea izan daitezke). Eragiketa erroreak besteen aldean kudea errazak dira, eta normalean nahikoa izaten da errorea erregistratzea. Gauzak konplikatuagoak izan daitezke garatzaile errore bat tupustean agertzen denean, aplikazioa egoera aldakorrean aurki baitaiteke. Horrelakoetan, aplikazioa berrabiarazi baino irtenbide hoberik ez duzu
|
||||
|
||||
### Kode adibidea: erroreak eragiketa errore (konfiantzazko) bihurtu
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
// errore objektu bat eragiketa errore bihurtu
|
||||
const nireErrorea = new Error(
|
||||
"Nola gehi dezaket produktu bat baliorik ez duenean?"
|
||||
);
|
||||
nireErrorea.funtzionatzenDu = true;
|
||||
|
||||
// edota errore eraikitzaile zentralizaturen bat erabiltzen baduzu (begiratu beste adibide batzuk "Erabili soilik “Errorea” objektu kapsulatua", 2.2, atalean)
|
||||
class AppErrorea {
|
||||
constructor(ohikoMota, deskribapena, funtzionatzenDu) {
|
||||
Error.call(this);
|
||||
Error.captureStackTrace(this);
|
||||
this.ohikoMota = ohikoMota;
|
||||
this.deskribapena = deskribapena;
|
||||
this.funtzionatzenDu = funtzionatzenDu;
|
||||
}
|
||||
}
|
||||
|
||||
throw new AppErrorea(
|
||||
erroreKudeatzailea.ohikoErroreak.SarreraOkerra,
|
||||
"Deskribatu hemen gertatutakoa",
|
||||
true
|
||||
);
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
// errore eraikitzaile zentralizatu batzuk (begiratu beste adibide batzuk "Erabili soilik “Errorea” objektu kapsulatua", 2.2, atalean)
|
||||
export class AppErrorea extends Error {
|
||||
public readonly ohikoMota: string;
|
||||
public readonly funtzionatzenDu: boolean;
|
||||
|
||||
constructor(
|
||||
ohikoMota: string,
|
||||
description: string,
|
||||
funtzionatzenDu: boolean
|
||||
) {
|
||||
super(description);
|
||||
|
||||
Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain
|
||||
|
||||
this.ohikoMota = ohikoMota;
|
||||
this.funtzionatzenDu = funtzionatzenDu;
|
||||
|
||||
Error.atzemanErrorePila(this);
|
||||
}
|
||||
}
|
||||
|
||||
// errore objektu bat eragiketa errore bihurtu (true)
|
||||
throw new AppErrorea(
|
||||
erroreKudeatzailea.ohikoErroreak.SarreraOkerra,
|
||||
"Deskribatu hemen gertatutakoa",
|
||||
true
|
||||
);
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Blogeko aipua: "Programatzaileen erroreak programazio erroreak dira programan"
|
||||
|
||||
Joyent blogeko “Node.js errore kudeaketa" hitz gako bati esker sailkatua
|
||||
|
||||
> …Programatzaile erroreak gainditzeko modurik hoberena berehala huts eragitea da. Huts egiteren bat gertatzean automatikoki berrekingo dituen berrekite sistemaren bat erabiliz exekutatu beharko zenituzte zure programak. Berrekite sistemei esker, huts egitea da modurik azkarrena programatzaile errore iragankorrak gertatzean zerbitzua berreskuratzeko modu fidagarrian…
|
||||
|
||||
### Blogeko aipua: "Alde egiteko modu segururik ez dago zehaztugabeko egoera hauskorrik sortu gabe"
|
||||
|
||||
Node.js dokumentazio ofizialetik hartua
|
||||
|
||||
> …Throw-ek JavaScripten nola funtzionatzen duen kontuan izanda, ez dago ia inoiz ataza bati modu seguruan “bertan behera utzitako puntuan segida ematerik” erreferentziak galdu gabe edota bestelako egoera hauskor zehaztugaberik sortu gabe. Jaurtitako erroreei erantzuteko modurik seguruena prozesua gelditzea da. Jakina, web zerbitzari arruntetan, konexio ugari eduki ahal ditzakezu irekita, eta ez da zentzuzkoa tupustean haiek ixtea beste batek eragindako errore batengatik. Planteamendu hoberena da errorea bidali duen eskariari errore erantzun bat bidaltzea, besteei beren atazak bukatzeko denbora emanez, eta eskari berriei kasu egiteari utzi prozesu horretan.
|
||||
|
||||
### Blogeko aipua: "Bestela zure aplikazioaren egoera arriskuan jar dezakezu"
|
||||
|
||||
debugable.com blogetik, “Node.js harrapatu gabeko exzepzioa" 3 hitz gakori esker sailkatua
|
||||
|
||||
> …Beraz, baldin eta benetan egiten ari zarena jakiten baduzu, “uncaughtException” exzepzio ebentua jaso ostean zure zerbitzuaren berrekite dotorea egin beharko zenuke. Bestela, zure aplikazioaren egoera arriskuan jar dezakezu, edota haren liburutegiak aldakor bihurtuarazi, mota guztietako errore zoroak eraginez…
|
||||
|
||||
### Blogeko aipua: "Errore kudeaketaren inguruko hiru ideia eskola daude"
|
||||
|
||||
JS Recipes blogetik hartua
|
||||
|
||||
> …Errore kudeaketaren inguruko hiru ideia eskola daude:
|
||||
|
||||
1. Utzi aplikazioak huts egin dezan eta ondoren berrekin.
|
||||
2. Kudeatu errore posible guztiak kudeatu eta inoiz ez huts egin.
|
||||
3. Bien arteko planteamendu bat.
|
||||
@ -1,10 +1,10 @@
|
||||
# Distinguish operational vs programmer errors
|
||||
# 동작상의 에러 vs 프로그래머 에러
|
||||
|
||||
### One Paragraph Explainer
|
||||
### 한문단 설명
|
||||
|
||||
Distinguishing the following two error types will minimize your app downtime and helps avoid crazy bugs: Operational errors refer to situations where you understand what happened and the impact of it – for example, a query to some HTTP service failed due to connection problem. On the other hand, programmer errors refer to cases where you have no idea why and sometimes where an error came from – it might be some code that tried to read an undefined value or DB connection pool that leaks memory. Operational errors are relatively easy to handle – usually logging the error is enough. Things become hairy when a programmer error pops up, the application might be in an inconsistent state and there’s nothing better you can do than to restart gracefully
|
||||
다음 두 가지의 에러 유형을 구별하면 앱 다운타임(downtime)을 최소화하고 심각한 버그를 방지하는데 도움이 될 것이다: 동작 오류는 발생한 일과 영향에 대해 어떤 상황인지 말한다 – 예를 들면, 연결 문제로 인한 일부 HTTP 서비스 쿼리 실패가 있다. 반면에, 프로그래머 에러는 어디에서 에러가 발생했는지 왜 발생했는지 모르는 경우를 말한다 – 이것은 정의되지 않은 값이나 메모리 누수되는 데이터베이스 연결 풀(connection pool)을 읽으려는 코드일 수 있다. 동작 상의 에러는 비교적 다루기 쉽다 – 보통은 에러를 기록하면 충분하다. 프로그래머 에러가 발생하면, 응용 프로그램이 일관된 상태가 아닐 수도 있으며 이 땐 다시 시작하는 것보다 더 좋은 방법은 없다
|
||||
|
||||
### Code Example – marking an error as operational (trusted)
|
||||
### 코드 예시 – 동작상의 에러 표시 (신뢰됨)
|
||||
|
||||
```javascript
|
||||
// marking an error object as operational
|
||||
@ -26,29 +26,29 @@ throw new AppError(errorManagement.commonErrors.InvalidInput, "Describe here wha
|
||||
|
||||
```
|
||||
|
||||
### Blog Quote: "Programmer errors are bugs in the program"
|
||||
### 블로그 인용: "프로그램에서 프로그래머 에러는 버그다"
|
||||
|
||||
From the blog, Joyent ranked 1 for the keywords “Node.js error handling”
|
||||
Joyent 블로그에서 "Node.js 에러 처리" 키워드 1위에 위치했다
|
||||
|
||||
> …The best way to recover from programmer errors is to crash immediately. You should run your programs using a restarter that will automatically restart the program in the event of a crash. With a restarter in place, crashing is the fastest way to restore reliable service in the face of a transient programmer error…
|
||||
> …프로그래머 에러를 복구하는 가장 좋은 방법은 즉시 충돌하는 것이다. 충돌 시 자동으로 프로그램을 다시 시작하는 리스타터(restarter)를 사용하여 프로그램을 실행해야 한다. 리스타터(restarter)를 사용하는 경우, 일시적인 프로그래머 오류에 직면하면 신뢰할 수 있는 서비스를 복구하는 가장 빠른 방법은 충돌이다…
|
||||
|
||||
### Blog Quote: "No safe way to leave without creating some undefined brittle state"
|
||||
### 블로그 인용: "정의되지 않은 취약 상태를 만들지 않고 떠나는 안전한 방법은 없다"
|
||||
|
||||
From Node.js official documentation
|
||||
Node.js 공식문서에서
|
||||
|
||||
> …By the very nature of how throw works in JavaScript, there is almost never any way to safely “pick up where you left off”, without leaking references, or creating some other sort of undefined brittle state. The safest way to respond to a thrown error is to shut down the process. Of course, in a normal web server, you might have many connections open, and it is not reasonable to abruptly shut those down because an error was triggered by someone else. The better approach is to send an error response to the request that triggered the error while letting the others finish in their normal time, and stop listening for new requests in that worker.
|
||||
> …자바스크립트에서 던지기(throw) 방식의 특성상, 정의되지 않은 종류의 취약 상태를 만들거나 참조 누수 없이는, 안전하게 "중단한 곳에서 픽업(pick up)" 할 수 있는 방법은 거의 없다. 던져진 에러를 처리하는 가장 안전한 방법은 프로세스를 종료하는 것이다. 물론, 일반적인 웹 서버에서는 많은 연결이 열려 있을 수 있으며, 다른 누군가에 의해 오류가 발생했을 수도 있기 때문에 갑자기 연결을 종료하는 것은 적절하지 않다. 더 나은 방법은 다른 사람들이 정상적인 시간에 완료할 수 있도록 하면서 에러를 발생시킨 요청에 대한 에러 응답을 보내고, 새 요청에 대한 응답을 중지하는 것이다.
|
||||
|
||||
### Blog Quote: "Otherwise you risk the state of your application"
|
||||
### 블로그 인용: "그렇지 않으면 당신의 애플리케이션 상태가 위험해질 수 있음"
|
||||
|
||||
From the blog, debugable.com ranked 3 for the keywords “Node.js uncaught exception”
|
||||
debugable.com 블로그에서 "Node.js 예상치 못한 예외 처리" 키워드 3위에 위치했다
|
||||
|
||||
> …So, unless you really know what you are doing, you should perform a graceful restart of your service after receiving an “uncaughtException” exception event. Otherwise, you risk the state of your application, or that of 3rd party libraries to become inconsistent, leading to all kinds of crazy bugs…
|
||||
> …그래서, 당신이 정말로 무엇을 하고 있는 지 모른다면, "예상치 못한 예외 처리(uncaughtException)" 예외 이벤트를 받은 후 서비스를 다시 시작해야한다. 그렇지 않으면, 애플리케이션 상태나 제 3자 라이브러리의 상태가 일관되지 않아 모든 종류의 심각한 버그가 발생할 위험이 있다…
|
||||
|
||||
### Blog Quote: "There are three schools of thoughts on error handling"
|
||||
### 블로그 인용: "에러 처리에는 주로 세 가지 방법이 있다"
|
||||
|
||||
From the blog: JS Recipes
|
||||
JS Recipes 블로그에서
|
||||
|
||||
> …There are primarily three schools of thoughts on error handling:
|
||||
1. Let the application crash and restart it.
|
||||
2. Handle all possible errors and never crash.
|
||||
3. A balanced approach between the two
|
||||
> …에러 처리에는 주로 세 가지 방법이 있다:
|
||||
1. 애플리케이션을 중지하고 다시 시작하기.
|
||||
2. 가능한 모든 에러를 처리하고 충돌하지 않게 하기.
|
||||
3. 이 두가지 사이의 균형잡힌 접근
|
||||
@ -1,20 +1,20 @@
|
||||
# Различайте операционные и программистские ошибки
|
||||
# Различайте операционные ошибки и ошибки программиста
|
||||
|
||||
### Объяснение в один абзац
|
||||
|
||||
Различение следующих двух типов ошибок минимизирует время простоя вашего приложения и помогает избежать сумасшедших ошибок: Операционные ошибки относятся к ситуациям, когда вы понимаете, что произошло, и влияние этого - например, запрос к какой-либо службе HTTP не выполнен из-за проблемы с подключением. С другой стороны, ошибки программиста относятся к случаям, когда вы не знаете, почему, а иногда и откуда возникла ошибка - это может быть какой-то код, который пытался прочитать неопределенное значение или пул соединений с БД, который приводит к утечке памяти. Операционные ошибки относительно легко обрабатываются - обычно достаточно регистрации ошибки. Вещи становятся неприятными, когда появляется ошибка программиста, приложение может быть в несовместимом состоянии, и нет ничего лучше, чем перезапуск изящно.
|
||||
Разделение ошибок на эти два типа минимизирует время простоя вашего приложения и помогает избежать сумасшедших ошибок: операционные ошибки относятся к ситуациям, когда вы понимаете происходящее и влияние ошибки на программу. Например, запрос к какой-нибудь службе HTTP не выполнен из-за проблемы с подключением. С другой стороны, ошибки программиста относятся к случаям, когда вы не знаете, почему, а иногда и откуда возникла ошибка - это может быть какой-то код, который пытался прочитать undefined-значение или код, который использует пул соединений с БД и приводит к утечке памяти. Операционные ошибки относительно легко обрабатываются - обычно достаточно логирования ошибки. Хуже становиться, когда появляется ошибка программиста, приложение может быть в несогласованном состоянии, и все, что вы можете сделать - перезапустить приложение.
|
||||
|
||||
### Пример кода - пометка ошибки как рабочей (доверенной)
|
||||
### Пример кода - помечаем ошибку как операционную (доверенную)
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
// marking an error object as operational
|
||||
const myError = new Error('How can I add new product when no value provided?');
|
||||
// помечаем объект ошибки, как операционный
|
||||
const myError = new Error('Как мы можем добавить продукт, если значение не задано?');
|
||||
myError.isOperational = true;
|
||||
|
||||
// or if you're using some centralized error factory (see other examples at the bullet "Use only the built-in Error object")
|
||||
// или, если вы используете централизированную фабрику ошибок (смотрите другие примеры в статье "Используйте только встроенный объект Error")
|
||||
class AppError {
|
||||
constructor (commonType, description, isOperational) {
|
||||
Error.call(this);
|
||||
@ -25,7 +25,7 @@ class AppError {
|
||||
}
|
||||
};
|
||||
|
||||
throw new AppError(errorManagement.commonErrors.InvalidInput, 'Describe here what happened', true);
|
||||
throw new AppError(errorManagement.commonErrors.InvalidInput, 'Описываем, что произошло', true);
|
||||
|
||||
```
|
||||
</details>
|
||||
@ -34,7 +34,7 @@ throw new AppError(errorManagement.commonErrors.InvalidInput, 'Describe here wha
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
// some centralized error factory (see other examples at the bullet "Use only the built-in Error object")
|
||||
// или, если вы используете централизированную фабрику ошибок (смотрите другие примеры в статье "Используйте только встроенный объект Error")
|
||||
export class AppError extends Error {
|
||||
public readonly commonType: string;
|
||||
public readonly isOperational: boolean;
|
||||
@ -42,7 +42,7 @@ export class AppError extends Error {
|
||||
constructor(commonType: string, description: string, isOperational: boolean) {
|
||||
super(description);
|
||||
|
||||
Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain
|
||||
Object.setPrototypeOf(this, new.target.prototype); // восстанавливаем цепочку прототипов
|
||||
|
||||
this.commonType = commonType;
|
||||
this.isOperational = isOperational;
|
||||
@ -51,7 +51,7 @@ export class AppError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
// marking an error object as operational (true)
|
||||
// помечаем объект ошибки, как операционный (true)
|
||||
throw new AppError(errorManagement.commonErrors.InvalidInput, 'Describe here what happened', true);
|
||||
|
||||
```
|
||||
@ -59,27 +59,27 @@ throw new AppError(errorManagement.commonErrors.InvalidInput, 'Describe here wha
|
||||
|
||||
### Цитата блога: "Ошибки программиста - это ошибки в программе"
|
||||
|
||||
Из блога Джойент, занявшему 1 место по ключевым словам "Обработка ошибок Node.js"
|
||||
Из блога Джойент, занявшего 1 место по ключевым словам "Обработка ошибок Node.js"
|
||||
|
||||
> … Лучший способ исправить ошибки программиста - это сразу же аварийно завершить работу. Вы должны запустить свои программы, используя перезапуск, который автоматически перезапустит программу в случае сбоя. С перезапуском на месте сбой является самым быстрым способом восстановления надежного сервиса перед лицом временной ошибки программиста …
|
||||
> … Лучший способ исправить ошибки программиста - это сразу же аварийно завершить работу. Вы должны запускать свои программы, используя сервис перезапуска, который автоматически будет перезапускать программу в случае сбоя. Сервис перезапуска является самым простым способом надежного восстановления сервиса при возникновении временной ошибки программиста…
|
||||
|
||||
### Цитата из блога: "Нет безопасного способа уйти, не создав неопределенного хрупкого состояния"
|
||||
### Цитата из блога: "Нет безопасного способа продолжить без возникновения хрупкого undefined-состояния системы"
|
||||
|
||||
Из официальной документации Node.js
|
||||
|
||||
> … По самой природе того, как throw работает в JavaScript, почти никогда не существует способа безопасно "выбрать то, на чем остановился", без утечки ссылок или создания какого-либо другого неопределенного хрупкого состояния. Самый безопасный способ отреагировать на возникшую ошибку - завершить процесс. Конечно, на обычном веб-сервере у вас может быть открыто много подключений, и нет смысла внезапно закрывать их, потому что кто-то еще вызвал ошибку. Лучший подход - отправить ответ об ошибке на запрос, который вызвал ошибку, позволяя остальным завершить работу в обычное время, и прекратить прослушивание новых запросов этого работника.
|
||||
> …По самой природе того, как throw работает в JavaScript, почти всегда нет способа безопасно "начать оттуда, где мы остановились", без утечки ссылок или создания другого undefined-состояния. Самый безопасный способ отреагировать на возникшую ошибку - завершить процесс. Конечно, на обычном веб-сервере у вас может быть открыто много подключений, и нет смысла внезапно закрывать все, потому что кто-то другой выбросил ошибку. Лучший вариант - отправить ответ об ошибке на запрос, который ее вызвал, позволяя остальным завершить работу в удобное время, и после прекратить прослушивание новых запросов в воркере, в котором возникла ошибка.
|
||||
|
||||
### Цитата блога: "В противном случае вы рискуете состоянием вашего приложения"
|
||||
|
||||
Из блога debugable.com, занявшего 3 место по ключевым словам "Node.js uncaught exception"
|
||||
|
||||
> … Итак, если вы действительно не знаете, что делаете, вам следует выполнить постепенный перезапуск службы после получения события исключения "uncaughtException". В противном случае вы рискуете привести к несогласованности состояния вашего приложения или сторонних библиотек, что приведет к всевозможным сумасшедшим ошибкам …
|
||||
> …Итак, если вы действительно не знаете, что делаете, вам следует выполнить постепенный перезапуск службы после получения события исключения "uncaughtException". В противном случае вы рискуете привести к несогласованности состояния вашего приложения или сторонних библиотек, что приведет к всевозможным сумасшедшим ошибкам…
|
||||
|
||||
### Цитата блога: "Есть три школы мысли об обработке ошибок"
|
||||
|
||||
Из блога: JS Recipes
|
||||
|
||||
> … Существует три основных направления работы с ошибками:
|
||||
> …Существует три основных направления работы с ошибками:
|
||||
1. Дайте приложению упасть и перезапустите его.
|
||||
2. Обрабатывайте все возможные ошибоки и никогда не роняйте.
|
||||
3. Сбалансированный подход между двумя предыдущими.
|
||||
2. Обрабатывайте все возможные ошибоки и никогда не роняйте сервис.
|
||||
3. Сбалансированный подход между двумя предыдущими.
|
||||
259
sections/errorhandling/returningpromises.basque.md
Normal file
259
sections/errorhandling/returningpromises.basque.md
Normal file
@ -0,0 +1,259 @@
|
||||
# Agintzak itzultzea
|
||||
|
||||
<br/>
|
||||
|
||||
### Azalpen paragrafoa
|
||||
|
||||
Errore bat gertatzen denean fluxu sinkrono edo asinkrono batetik abiatuta, derrigorrezkoa da errore fluxuaren pila aztarna osoa edukitzea. Harrigarria bada ere, funtzio asinkrono batek (adibidez beste funtzio asinkrono bat deitzen duena) itxaron gabe (await) promesak itzultzen dituenean, errore bat gertatuko litzateke eta jatorrizko funtzio horren izena ez litzateke pilaren aztarnan agertu beharko. Horrek informazio partziala emango dio errorea diagnostikatzen duenari, are gehiago errorearen zergatiak jatorrizko funtzioan badu oinarria. Badago "zero-kostuko pila aztarna asinkronoak" deitzen den v8 funtzionalitate bat, pila aztarnak azken gertatu berri den `await`ean moztuak ez izatea ahalbidetzen duena. Garrantzirik gabeko inplementazio xehetasunak direla eta, horrek ez du funtzionatuko funtzioak bueltatzen duen balioa (sinkronoa edo asinkronoa), promesa bat baldin bada. Promesak deusezten direnean pilaren aztarnan zuloak egotea ekiditeoko, promesak beti esplizituki ebatzi behar ditugu `await` erabiliz beraiek funtzioetatik bueltatu baino lehen
|
||||
|
||||
<br/>
|
||||
|
||||
### Anti ereduaren kode adibidea: funtzio asinkronoak deitu itxaron gabe
|
||||
|
||||
<details><summary>Javascript</summary>
|
||||
<p>
|
||||
|
||||
```javascript
|
||||
async function asyncJaurti(mezua) {
|
||||
await null // benetako asinkronoa den zerbaiti itxaron beharra (begiratu #2 puntua)
|
||||
throw Error(mezua)
|
||||
}
|
||||
|
||||
async function bueltatuItxaronGabe () {
|
||||
return asyncJaurti('bueltatuItxaronGabe falta da pilaren aztarnan')
|
||||
}
|
||||
|
||||
// 👎 EZ du edukiko bueltatuItxaronGabe pilaren aztarnan
|
||||
bueltatuItxaronGabe().catch(console.log)
|
||||
```
|
||||
|
||||
erregistratuko du
|
||||
|
||||
```
|
||||
Errorea: bueltatuItxaronGabe falta da pilaren aztarnan
|
||||
asyncJaurti-ren barruan ([...])
|
||||
```
|
||||
</p>
|
||||
</details>
|
||||
|
||||
### Kode adibidea: zuzenean deitu eta itxaron
|
||||
|
||||
<details><summary>Javascript</summary>
|
||||
<p>
|
||||
|
||||
```javascript
|
||||
async function asyncJaurti(mezua) {
|
||||
await null // benetako asinkronoa den zerbaiti itxaron beharra (begiratu #2 puntua)
|
||||
throw Error(mezua)
|
||||
}
|
||||
|
||||
async function bueltatuItxaronda() {
|
||||
return await asyncJaurti('zati guztiak edukiz')
|
||||
}
|
||||
|
||||
// 👍bueltatuItxaronda edukiko du pilaren aztarnan
|
||||
bueltatuItxaronda().catch(console.log)
|
||||
```
|
||||
|
||||
erregistratuko du
|
||||
|
||||
```
|
||||
Error: zati guztiak edukiz
|
||||
asyncJaurti-ren barruan ([...])
|
||||
bueltatuItxaronda-ren barruan ([...])
|
||||
```
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<br/>
|
||||
|
||||
### Anti ereduaren kode adibidea: itzuli promesak funtzioak asinkronotzat etiketatu gabe
|
||||
|
||||
<details><summary>Javascript</summary>
|
||||
<p>
|
||||
|
||||
```javascript
|
||||
async function asyncJaurti () {
|
||||
await null // benetako asinkronoa den zerbaiti itxaron beharra (begiratu #2 puntua)
|
||||
throw Error('syncFn falta da pilaren aztarnan')
|
||||
}
|
||||
|
||||
function syncFn () {
|
||||
return asyncJaurti()
|
||||
}
|
||||
|
||||
async function asyncFn () {
|
||||
return await syncFn()
|
||||
}
|
||||
|
||||
// 👎 ez dut edukiko syncFn pilaren aztarnan promesak itzultzen dituelako sinkronizatzen den ari den bitartean
|
||||
asyncFn().catch(console.log)
|
||||
```
|
||||
|
||||
erregistratuko du
|
||||
|
||||
```
|
||||
Error: syncFn falta da pilaren aztarnan
|
||||
asyncJaurti-ren barruan ([...])
|
||||
async asyncFn-en barruan ([...])
|
||||
```
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
### Kode adibidea: etiketatu promesak asinkrono gisa itzultzen dituen funtzioa
|
||||
|
||||
<details><summary>Javascript</summary>
|
||||
<p>
|
||||
|
||||
```javascript
|
||||
async function asyncJaurti () {
|
||||
await null // benetako asinkronoa den zerbaiti itxaron beharra (begiratu #2 puntua)
|
||||
throw Error('zati guztiak edukiz')
|
||||
}
|
||||
|
||||
async function syncEtikAsyncFnraAldatua() {
|
||||
return await asyncJaurti()
|
||||
}
|
||||
|
||||
async function asyncFn () {
|
||||
return await syncEtikAsyncFnraAldatua()
|
||||
}
|
||||
|
||||
// 👍 orain syncEtikAsyncFnraAldatua pilaren aztarnan agertuko da
|
||||
asyncFn().catch(console.log)
|
||||
```
|
||||
|
||||
erregistratuko du
|
||||
|
||||
```
|
||||
Error: zati guztiak edukiz
|
||||
asyncJaurti-ren barruan ([...])
|
||||
syncEtikAsyncFnraAldatua-ren barruan ([...])
|
||||
async asyncFn-en barruan ([...])
|
||||
```
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
</br>
|
||||
|
||||
### Kode adibidea, anti eredua #3: callback asinkronoen erabilera zuzena callback sinkronoa espero zen lekuan
|
||||
|
||||
<details><summary>Javascript</summary>
|
||||
<p>
|
||||
|
||||
```javascript
|
||||
async function berreskuratuErabiltzailea (id) {
|
||||
await null
|
||||
if (!id) throw Error('pilaren aztarna falta da berreskuratuErabiltzailea deitu den lekuan')
|
||||
return {id}
|
||||
}
|
||||
|
||||
const erabiltzaileIdak = [1, 2, 0, 3]
|
||||
|
||||
// 👎 pilaren aztarnak berreskuratuErabiltzailea funtzioa edukiko du baina ez du zehaztuko non izan den deitua
|
||||
Promise.all(erabiltzaileIdak.map(berreskuratuErabiltzailea)).catch(console.log)
|
||||
```
|
||||
|
||||
erregistratuko du
|
||||
|
||||
```
|
||||
Error: pilaren aztarna falta da berreskuratuErabiltzailea deitu den lekuan
|
||||
berreskuratuErabiltzailea-en barruan ([...])
|
||||
async Promise.all-en barruan (index 2)
|
||||
```
|
||||
|
||||
*Apunte bat*: pentsa liteke `Promise.all (index 2)`ek `berreskuratuErabiltzailea` deitua izan den lekua ulertzen lagundu dezakela, baina [guztiz ezberdina den v8ko akatsa](https://bugs.chromium.org/p/v8/issues/detail?id=9023) dela eta, `(index 2)` v8 barneko lerro bat da
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
### Kode adibidea: bildu callback asinkronoa funtzio asinkrono faltsu batean callback sinkrono gisa bidali aurretik
|
||||
|
||||
<details><summary>Javascript</summary>
|
||||
<p>
|
||||
|
||||
*1.oharra*: callbacka deituko duen funtzioaren kodea kontrolatuz gero, soilik aldatu funtzio hau asinkronora eta gehitu `await` callback deiaren aurretik. Callbacka deitzen duen kodearen ardurandu ez zarela kontsideratu dut behean (edo honen aldaketa onartezina da adibidez atzeranzko-konpatibilitatea dela eta)
|
||||
|
||||
*2.oharra*: sarri, callback sinrkono bat espero den lekuetan callback asinkronoak erabiltzeak ez du inola ere funtzionatuko. Hau ez da funtzionatzen ez duen kodea nola konpontzeari buruz, kodea behar bezala funtzionatzen ari denean pilaren aztarna nola konpontzeari buruz baizik
|
||||
|
||||
```javascript
|
||||
async function berreskuratuErabiltzailea (id) {
|
||||
await null
|
||||
if (!id) throw Error('zati guztiak edukiz')
|
||||
return {id}
|
||||
}
|
||||
|
||||
const erabiltzaileIdak = [1, 2, 0, 3]
|
||||
|
||||
// 👍 orain azpiko lerroa pilaren aztarnan dago
|
||||
Promise.all(erabiltzaileIdak.map(async id => await berreskuratuErabiltzailea(id))).catch(console.log)
|
||||
```
|
||||
|
||||
erregistratuko du
|
||||
|
||||
```
|
||||
Error: zati guztiak edukiz
|
||||
berreskuratuErabiltzailea-ren barruan ([...])
|
||||
async-en barruan ([...])
|
||||
async Promise.all-en barruan (index 2)
|
||||
```
|
||||
|
||||
`map` barruko `await` explizituari esker, `async-ren barruan ([...])` lerroaren bukaerak `berreskuratuErabiltzailea` deitua izan den puntu zehatza adieraziko du
|
||||
|
||||
*Apunte bat*: `berreskuratuErabiltzailea` biltzen duen funtzio asinkrono batek `await` ahazten badu zerbait bueltatu aurretik (anti-eredua #1 + anti-eredua #3), zati bat bakarrik izango da mantendua pilaren aztarnan:
|
||||
|
||||
|
||||
```javascript
|
||||
[...]
|
||||
|
||||
// 👎 anti-pattern 1 + anti-pattern 3 - only one frame left in stacktrace
|
||||
Promise.all(erabiltzaileIdak.map(async id => berreskuratuErabiltzailea(id))).catch(console.log)
|
||||
```
|
||||
|
||||
erregistratuko du
|
||||
|
||||
```
|
||||
Error: [...]
|
||||
berreskuratuErabiltzailea-ren barruan ([...])
|
||||
```
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<br/>
|
||||
|
||||
Zero kostuko pila aztarna asinkronoak" deitzen den v8 funtzionalitate bat
|
||||
|
||||
## Azalpen aurreratua
|
||||
|
||||
Oso ezberdinak dira funtzio sinkronoen pila aztarnen eta funtzio asinkronoen pila aztarnen mekanismoak v8ren ezarpenetan: pila aztarna asinkronoa oinarritua dago Node.js martxan dagoen sistema eragileak emandako **pila**n (programazio lengoaia gehienak bezala). Funtzio asinkrono bat exekutatzen ari denean, sistema eragileko **pila** agerian jartzen da funtzioa bere lehen `await`era iristen den momentuan. Beraz, pilaren aztarna nahasketa bat da, hain zuzen, sistema eragilearen pilaren eta baztertutako **promesa ebazpen katea**rena. Zero kostuko pila aztarna asinkronoen ezarpenak **promesa ebazpen katea** luzatzen du bakarrik promesa `itxaroten` <span>[¹](#1)</span> ari den bitartean. Funtzio asinkronoek bakarrik (`async`) itxaron (`await`) ahal dutenez, beti galduko da funtzio asinkronoa pilaren aztarna asinkrono batean, operazio asinkronoren bat izan bada funtzioa deitu eta gero <span>[²](#2)</span>
|
||||
|
||||
### The tradeoff (sektorea)
|
||||
|
||||
`await` bakoitzak mikro ataza berri bat sortzen du gertaeraren begiztan. Beraz `await` gehiago gehitzeak errendimendu zigorra ekarriko luke. Hala ere, sareak edota datu baseak sortutako errendimendu isuna [ikaragarri handiagoa](https://colin-scott.github.io/personal_website/research/interactive_latency.html) da, eta, beraz gehitutako `await`aren zigorra ez da zerbitzariak edo CLIak garatzeko orduan kontutan hartu beharreko zerbait, eskaera edo komando bakoitzeko oso kode beroa izan ezean behintzat. Orduan, `await` ezabatzeak `return await`etan errendimendu bultzada nabarmena bilatzeko azken lekua izan beharko luke eta, zalantzarik gabe, inoiz ez litzateke aldez aurretik egin beharko
|
||||
|
||||
|
||||
### Zergatik jotzen zen await bueltatzea anti eredutzat iraganean
|
||||
|
||||
[Artikulu bikain](https://jakearchibald.com/2017/await-vs-return-vs-return-await/) ugari daude azaltzen dutenak zergatik `return await`ak ez diren inoiz `try` bloketik kanpo erabili behar, bai eta [ESLint arau](https://eslint.org/docs/rules/no-return-await) arau bat ere hori debekatzen duena. Horren arrazoia da async/await Node.js 0.10ko transpilagailuekin erabilgarri bihurtu izana (eta jatorrizko laguntza lortu dutela Node.js 7.6 bertsioan) eta "zero kostuko pila aztarna asinkronoak" Node.js 10en gehitua izana eta ondoren Node.js 12tik kendua, `return await` eta `return` guztiz parekoak ziren, edozein `try` kode bloketik kanpo. Oraindik ere berdina izaten jarraituko du seguraski ES motoreentzat. Horregatik, Node.jsentzat jardunbide egokiena da promesak kalkulatzea beraiek bueltatu aurretik. EcmaScriptentzat, ordea, hori ez jardunbide egokiena.
|
||||
|
||||
### Oharrak:
|
||||
|
||||
1. Pila aztarna asinkronoak halako ezarpen korapilatsua izatearen beste arrazoi bat da pila aztarna beti modu sinkronoan eraiki behar dela, gertaeraren begiztaren <span id="a1">[¹](#1)</span> momentu berean
|
||||
|
||||
2. `throwAsync` barruan `await` gabe, gertaera begiztaren fase berean exekutatuko litzateke kodea. Hori, degeneratutako kasua da: sistema eragilearen **pila** ez litzateke hustuko, eta pila aztarna beteko litzateke funtzioaren emaitzari berariaz itxaron gabe ere. Normalean, promesen erabilerak operazio asinkrono batzuk edukitzen dituenez, pilaren aztarnaren zati batzuk galdu egingo lirateke
|
||||
|
||||
3. Zero kostuko pila aztarna asinkronoek ez lukete funtzionatuko promesa erabileren kasu korapilatsuetan: promesa bakar bati hainbat aldiz eta leku ezberdinetan itxaron beharra dagoenean, adibidez.
|
||||
|
||||
|
||||
### Erreferentziak:
|
||||
<span id="1">1. </span>[v8ko zero kostuko pila aztarna asinkronoak blog argitarapena](https://v8.dev/blog/fast-async)
|
||||
<br>
|
||||
|
||||
<span id="2">2. </span>[zero kostuko pila aztarna asinkronoei inguruko dokumentazioa ezarpen xehetasunekin hemen](
|
||||
https://docs.google.com/document/d/13Sy_kBIJGP0XT34V1CV3nkWya4TwYx9L3Yv45LdGB6Q/edit
|
||||
)
|
||||
<br>
|
||||
285
sections/errorhandling/returningpromises.md
Normal file
285
sections/errorhandling/returningpromises.md
Normal file
@ -0,0 +1,285 @@
|
||||
# Returning promises
|
||||
|
||||
<br/>
|
||||
|
||||
### One Paragraph Explainer
|
||||
|
||||
When an error occurs, whether from a synchronous or asynchronous flow, it's imperative to have a full stacktrace of the error flow. Surprisingly, if an async function returns a promise (e.g., calls other async function) without awaiting, should an error occur then the caller function won't appear in the stacktrace. This will leave the person who diagnoses the error with partial information - All the more if the error cause lies within that caller function. There is a feature v8 called "zero-cost async stacktraces" that allow stacktraces not to be cut on the most recent `await`. But due to non-trivial implementation details, it will not work if the return value of a function (sync or async) is a promise. So, to avoid holes in stacktraces when returned promises would be rejected, we must always explicitly resolve promises with `await` before returning them from functions
|
||||
|
||||
<br/>
|
||||
|
||||
### Code example Anti-Pattern: Calling async function without awaiting
|
||||
|
||||
<details><summary>Javascript</summary>
|
||||
<p>
|
||||
|
||||
```javascript
|
||||
async function throwAsync(msg) {
|
||||
await null // need to await at least something to be truly async (see note #2)
|
||||
throw Error(msg)
|
||||
}
|
||||
|
||||
async function returnWithoutAwait () {
|
||||
return throwAsync('missing returnWithoutAwait in the stacktrace')
|
||||
}
|
||||
|
||||
// 👎 will NOT have returnWithoutAwait in the stacktrace
|
||||
returnWithoutAwait().catch(console.log)
|
||||
```
|
||||
|
||||
would log
|
||||
|
||||
```
|
||||
Error: missing returnWithoutAwait in the stacktrace
|
||||
at throwAsync ([...])
|
||||
```
|
||||
</p>
|
||||
</details>
|
||||
|
||||
### Code example: Calling and awaiting as appropriate
|
||||
|
||||
<details><summary>Javascript</summary>
|
||||
<p>
|
||||
|
||||
```javascript
|
||||
async function throwAsync(msg) {
|
||||
await null // need to await at least something to be truly async (see note #2)
|
||||
throw Error(msg)
|
||||
}
|
||||
|
||||
async function returnWithAwait() {
|
||||
return await throwAsync('with all frames present')
|
||||
}
|
||||
|
||||
// 👍 will have returnWithAwait in the stacktrace
|
||||
returnWithAwait().catch(console.log)
|
||||
```
|
||||
|
||||
would log
|
||||
|
||||
```
|
||||
Error: with all frames present
|
||||
at throwAsync ([...])
|
||||
at async returnWithAwait ([...])
|
||||
```
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<br/>
|
||||
|
||||
### Code example Anti-Pattern: Returning a promise without tagging the function as async
|
||||
|
||||
<details><summary>Javascript</summary>
|
||||
<p>
|
||||
|
||||
```javascript
|
||||
async function throwAsync () {
|
||||
await null // need to await at least something to be truly async (see note #2)
|
||||
throw Error('missing syncFn in the stacktrace')
|
||||
}
|
||||
|
||||
function syncFn () {
|
||||
return throwAsync()
|
||||
}
|
||||
|
||||
async function asyncFn () {
|
||||
return await syncFn()
|
||||
}
|
||||
|
||||
// 👎 syncFn would be missing in the stacktrace because it returns a promise while been sync
|
||||
asyncFn().catch(console.log)
|
||||
```
|
||||
|
||||
would log
|
||||
|
||||
```
|
||||
Error: missing syncFn in the stacktrace
|
||||
at throwAsync ([...])
|
||||
at async asyncFn ([...])
|
||||
```
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
### Code example: Tagging the function that returns a promise as async
|
||||
|
||||
<details><summary>Javascript</summary>
|
||||
<p>
|
||||
|
||||
```javascript
|
||||
async function throwAsync () {
|
||||
await null // need to await at least something to be truly async (see note #2)
|
||||
throw Error('with all frames present')
|
||||
}
|
||||
|
||||
async function changedFromSyncToAsyncFn () {
|
||||
return await throwAsync()
|
||||
}
|
||||
|
||||
async function asyncFn () {
|
||||
return await changedFromSyncToAsyncFn()
|
||||
}
|
||||
|
||||
// 👍 now changedFromSyncToAsyncFn would present in the stacktrace
|
||||
asyncFn().catch(console.log)
|
||||
```
|
||||
|
||||
would log
|
||||
|
||||
```
|
||||
Error: with all frames present
|
||||
at throwAsync ([...])
|
||||
at changedFromSyncToAsyncFn ([...])
|
||||
at async asyncFn ([...])
|
||||
```
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
</br>
|
||||
|
||||
### Code Example Anti-pattern #3: direct usage of async callback where sync callback is expected
|
||||
|
||||
<details><summary>Javascript</summary>
|
||||
<p>
|
||||
|
||||
```javascript
|
||||
async function getUser (id) {
|
||||
await null
|
||||
if (!id) throw Error('stacktrace is missing the place where getUser has been called')
|
||||
return {id}
|
||||
}
|
||||
|
||||
const userIds = [1, 2, 0, 3]
|
||||
|
||||
// 👎 the stacktrace would include getUser function but would give no clue on where it has been called
|
||||
Promise.all(userIds.map(getUser)).catch(console.log)
|
||||
```
|
||||
|
||||
would log
|
||||
|
||||
```
|
||||
Error: stacktrace is missing the place where getUser has been called
|
||||
at getUser ([...])
|
||||
at async Promise.all (index 2)
|
||||
```
|
||||
|
||||
*Side-note*: it may looks like `Promise.all (index 2)` can help understanding the place where `getUser` has been called,
|
||||
but due to a [completely different bug in v8](https://bugs.chromium.org/p/v8/issues/detail?id=9023), `(index 2)` is
|
||||
a line from internals of v8
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
### Code example: wrap async callback in a dummy async function before passing it as a sync callback
|
||||
|
||||
<details><summary>Javascript</summary>
|
||||
<p>
|
||||
|
||||
*Note 1*: in case if you control the code of the function that would call the callback - just change that function to
|
||||
async and add `await` before the callback call. Below I assume that you are not in charge of the code that is calling
|
||||
the callback (or it's change is unacceptable for example because of backward compatibility)
|
||||
|
||||
*Note 2*: quite often usage of async callback in places where sync one is expected would not work at all. This is not about
|
||||
how to fix the code that is not working - it's about how to fix stacktrace in case if code is already working as
|
||||
expected
|
||||
|
||||
```javascript
|
||||
async function getUser (id) {
|
||||
await null
|
||||
if (!id) throw Error('with all frames present')
|
||||
return {id}
|
||||
}
|
||||
|
||||
const userIds = [1, 2, 0, 3]
|
||||
|
||||
// 👍 now the line below is in the stacktrace
|
||||
Promise.all(userIds.map(async id => await getUser(id))).catch(console.log)
|
||||
```
|
||||
|
||||
would log
|
||||
|
||||
```
|
||||
Error: with all frames present
|
||||
at getUser ([...])
|
||||
at async ([...])
|
||||
at async Promise.all (index 2)
|
||||
```
|
||||
|
||||
where thanks to explicit `await` in `map`, the end of the line `at async ([...])` would point to the exact place where
|
||||
`getUser` has been called
|
||||
|
||||
*Side-note*: if async function that wrap `getUser` would miss `await` before return (anti-pattern #1 + anti-pattern #3)
|
||||
then only one frame would left in the stacktrace:
|
||||
|
||||
```javascript
|
||||
[...]
|
||||
|
||||
// 👎 anti-pattern 1 + anti-pattern 3 - only one frame left in stacktrace
|
||||
Promise.all(userIds.map(async id => getUser(id))).catch(console.log)
|
||||
```
|
||||
|
||||
would log
|
||||
|
||||
```
|
||||
Error: [...]
|
||||
at getUser ([...])
|
||||
```
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<br/>
|
||||
|
||||
## Advanced explanation
|
||||
|
||||
The mechanisms behind sync functions stacktraces and async functions stacktraces in v8 implementation are quite different:
|
||||
sync stacktrace is based on **stack** provided by operating system Node.js is running on (just like in most programming
|
||||
languages). When an async function is executing, the **stack** of operating system is popping it out as soon as the
|
||||
function is getting to it's first `await`. So async stacktrace is a mix of operating system **stack** and a rejected
|
||||
**promise resolution chain**. Zero-cost async stacktraces implementation is extending the **promise resolution chain**
|
||||
only when the promise is getting `awaited` <span>[¹](#1)</span>. Because only `async` functions may `await`,
|
||||
sync function would always be missed in async stacktrace if any async operation has been performed after the function
|
||||
has been called <span>[²](#2)</span>
|
||||
|
||||
### The tradeoff
|
||||
|
||||
Every `await` creates a new microtask in the event loop, so adding more `await`s to the code would
|
||||
introduce some performance penalty. Nevertheless, the performance penalty introduced by network or
|
||||
database is [tremendously larger](https://colin-scott.github.io/personal_website/research/interactive_latency.html)
|
||||
so additional `await`s penalty is not something that should be considered during web servers or CLI
|
||||
development unless for a very hot code per request or command. So removing `await`s in
|
||||
`return await`s should be one of the last places to search for noticeable performance boost and
|
||||
definitely should never be done up-front
|
||||
|
||||
|
||||
### Why return await was considered as anti-pattern in the past
|
||||
|
||||
There is a number of [excellent articles](https://jakearchibald.com/2017/await-vs-return-vs-return-await/) explained
|
||||
why `return await` should never be used outside of `try` block and even an
|
||||
[ESLint rule](https://eslint.org/docs/rules/no-return-await) that disallows it. The reason for that is the fact that
|
||||
since async/await become available with transpilers in Node.js 0.10 (and got native support in Node.js 7.6) and until
|
||||
"zero-cost async stacktraces" was introduced in Node.js 10 and unflagged in Node.js 12, `return await` was absolutely
|
||||
equivalent to `return` for any code outside of `try` block. It may still be the same for some other ES engines. This
|
||||
is why resolving promises before returning them is the best practice for Node.js and not for the EcmaScript in general
|
||||
|
||||
### Notes:
|
||||
|
||||
1. One another reason why async stacktrace has such tricky implementation is the limitation that stacktrace
|
||||
must always be built synchronously, on the same tick of event loop <span id="a1">[¹](#1)</span>
|
||||
2. Without `await` in `throwAsync` the code would be executed in the same phase of event loop. This is a
|
||||
degenerated case when OS **stack** would not get empty and stacktrace be full even without explicitly
|
||||
awaiting the function result. Usually usage of promises include some async operations and so parts of
|
||||
the stacktrace would get lost
|
||||
3. Zero-cost async stacktraces still would not work for complicated promise usages e.g. single promise
|
||||
awaited many times in different places
|
||||
|
||||
### References:
|
||||
<span id="1">1. </span>[Blog post on zero-cost async stacktraces in v8](https://v8.dev/blog/fast-async)
|
||||
<br>
|
||||
|
||||
<span id="2">2. </span>[Document on zero-cost async stacktraces with mentioned here implementation details](
|
||||
https://docs.google.com/document/d/13Sy_kBIJGP0XT34V1CV3nkWya4TwYx9L3Yv45LdGB6Q/edit
|
||||
)
|
||||
<br>
|
||||
289
sections/errorhandling/returningpromises.russian.md
Normal file
289
sections/errorhandling/returningpromises.russian.md
Normal file
@ -0,0 +1,289 @@
|
||||
# Возвращение промисов
|
||||
|
||||
<br/>
|
||||
|
||||
### Короткое объяснение
|
||||
|
||||
У v8 есть особая способность, называемая "бесплатные асинхронные стектрейсы", которая позволяет стектрейсам не
|
||||
обрываться на самом позднем `await`. Но, из-за нетривиальных нюансов реализации, она не сработает если возвращаемое
|
||||
значение функции (синхронной или асинхронной) является промис. По этому, для того чтобы избежать дыр в стектрейсах
|
||||
после отказа (rejection) возвращаемого промиса, следует всегда явно разрешать (resolve) промисы при помощи `await`
|
||||
перед тем как возвращать их из функций
|
||||
|
||||
<br/>
|
||||
|
||||
### Анти-паттерн №1: return \<promise>
|
||||
|
||||
<details><summary>Javascript</summary>
|
||||
<p>
|
||||
|
||||
```javascript
|
||||
async function throwAsync(msg) {
|
||||
await null // нужно выполнить await для того что бы функция была по-настоящему асинхронной (см. заметку №2)
|
||||
throw Error(msg)
|
||||
}
|
||||
|
||||
async function returnWithoutAwait () {
|
||||
return throwAsync('missing returnWithoutAwait in the stacktrace')
|
||||
}
|
||||
|
||||
// 👎 returnWithoutAwait будет отсутствовать в стектрейсе
|
||||
returnWithoutAwait().catch(console.log)
|
||||
```
|
||||
|
||||
выведет в лог
|
||||
|
||||
```
|
||||
Error: missing returnWithoutAwait in the stacktrace
|
||||
at throwAsync ([...])
|
||||
```
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
### Как правильно: return await \<promise>
|
||||
|
||||
<details><summary>Javascript</summary>
|
||||
<p>
|
||||
|
||||
```javascript
|
||||
async function throwAsync(msg) {
|
||||
await null // нужно выполнить await для того что бы функция была по-настоящему асинхронной (см. заметку №2)
|
||||
throw Error(msg)
|
||||
}
|
||||
|
||||
async function returnWithAwait() {
|
||||
return await throwAsync('with all frames present')
|
||||
}
|
||||
|
||||
// 👍 returnWithAwait будет присутствовать в стектрейсе
|
||||
returnWithAwait().catch(console.log)
|
||||
```
|
||||
|
||||
выведет в лог
|
||||
|
||||
```
|
||||
Error: with all frames present
|
||||
at throwAsync ([...])
|
||||
at async returnWithAwait ([...])
|
||||
```
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<br/>
|
||||
|
||||
### Анти-паттерн №2: синхронная функция возвращающая промис
|
||||
|
||||
<details><summary>Javascript</summary>
|
||||
<p>
|
||||
|
||||
```javascript
|
||||
async function throwAsync () {
|
||||
await null // нужно выполнить await для того что бы функция была по-настоящему асинхронной (см. заметку №2)
|
||||
throw Error('missing syncFn in the stacktrace')
|
||||
}
|
||||
|
||||
function syncFn () {
|
||||
return throwAsync()
|
||||
}
|
||||
|
||||
async function asyncFn () {
|
||||
return await syncFn()
|
||||
}
|
||||
|
||||
// 👎 syncFn будет отсутствовать в стектрейсе так как она синхронная и возвращает промис
|
||||
asyncFn().catch(console.log)
|
||||
```
|
||||
|
||||
would log
|
||||
|
||||
```
|
||||
Error: missing syncFn in the stacktrace
|
||||
at throwAsync ([...])
|
||||
at async asyncFn ([...])
|
||||
```
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
### Как правильо: объявить функцию возвращающую промис как асинхронную
|
||||
|
||||
<details><summary>Javascript</summary>
|
||||
<p>
|
||||
|
||||
```javascript
|
||||
async function throwAsync () {
|
||||
await null // нужно выполнить await для того что бы функция была по-настоящему асинхронной (см. заметку №2)
|
||||
throw Error('with all frames present')
|
||||
}
|
||||
|
||||
async function changedFromSyncToAsyncFn () {
|
||||
return await throwAsync()
|
||||
}
|
||||
|
||||
async function asyncFn () {
|
||||
return await changedFromSyncToAsyncFn()
|
||||
}
|
||||
|
||||
// 👍 теперь changedFromSyncToAsyncFn будет присутствовать в стектрейсе
|
||||
asyncFn().catch(console.log)
|
||||
```
|
||||
|
||||
would log
|
||||
|
||||
```
|
||||
Error: with all frames present
|
||||
at throwAsync ([...])
|
||||
at changedFromSyncToAsyncFn ([...])
|
||||
at async asyncFn ([...])
|
||||
```
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
</br>
|
||||
|
||||
### Анти-паттерн №3: прямая передача асинхронного коллбэка в месте где ожидается синхронный коллбек
|
||||
|
||||
<details><summary>Javascript</summary>
|
||||
<p>
|
||||
|
||||
```javascript
|
||||
async function getUser (id) {
|
||||
await null
|
||||
if (!id) throw Error('stacktrace is missing the place where getUser has been called')
|
||||
return {id}
|
||||
}
|
||||
|
||||
const userIds = [1, 2, 0, 3]
|
||||
|
||||
// 👎 хотя в стектрейсе будет присутствовать функция getUser, в нем не будет места где она была вызвана
|
||||
Promise.all(userIds.map(getUser)).catch(console.log)
|
||||
```
|
||||
|
||||
выведет в лог
|
||||
|
||||
```
|
||||
Error: stacktrace is missing the place where getUser has been called
|
||||
at getUser ([...])
|
||||
at async Promise.all (index 2)
|
||||
```
|
||||
|
||||
*Между прочим*: может показаться что `Promise.all (index 2)` может помоч понять где `getUser` была вызвана, но из-за
|
||||
[совершенно другого бага в v8](https://bugs.chromium.org/p/v8/issues/detail?id=9023), `(index 2)` является строкой из
|
||||
внутреннего кода v8
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
### Как правильно: обернуть асинхронный коллбэк в асинхронную функция перед тем как передать его как синхронный коллбэк
|
||||
|
||||
<details><summary>Javascript</summary>
|
||||
<p>
|
||||
|
||||
*Заметка 1*: в случае если вы отвечаете за код функции которая в итоге вызовет коллбэк - просто сделаете ее асинхронной и
|
||||
добавьте `await` перед вызовом коллбэка. Далее я предполагаю что вы не имеете контроля над кодом функции которая
|
||||
вызывает коллбэк (или ее изменение таким образом недопустимо, например, из соображений обратной совместимости)
|
||||
|
||||
*Заметка 2*: Имейте ввиду, часто передача асинхронного коллбэка в место где ожидается синхронный коллбэк вообще не будет работать.
|
||||
Тут описывается не как починить такой код а лишь как починить стектрейсы если код уже работает как ожидается
|
||||
|
||||
```javascript
|
||||
async function getUser (id) {
|
||||
await null
|
||||
if (!id) throw Error('with all frames present')
|
||||
return {id}
|
||||
}
|
||||
|
||||
const userIds = [1, 2, 0, 3]
|
||||
|
||||
// 👍 теперь строка вызова getUser присутствует в стектрейсе
|
||||
Promise.all(userIds.map(async id => await getUser(id))).catch(console.log)
|
||||
```
|
||||
|
||||
выведет в лог
|
||||
|
||||
```
|
||||
Error: with all frames present
|
||||
at getUser ([...])
|
||||
at async ([...])
|
||||
at async Promise.all (index 2)
|
||||
```
|
||||
|
||||
где, благодаря явному `await` в `map`, конец строки `at async ([...])` указывает на место где `getUser` была вызвана
|
||||
|
||||
*Между прочим*: если оберточная асинхронная функция для `getUser` не сделает явный `await` перед возвратом (то есть
|
||||
комбинация анти-паттерн 1 + анти-паттерн 3), то стектрейс останется вообще всегда с одним кадром:
|
||||
|
||||
```javascript
|
||||
[...]
|
||||
|
||||
// 👎 анти-паттерн 1 + анти-паттерн 3 - в стектрейсе осталась только getUser
|
||||
Promise.all(userIds.map(async id => getUser(id))).catch(console.log)
|
||||
```
|
||||
|
||||
выведет в лог
|
||||
|
||||
```
|
||||
Error: [...]
|
||||
at getUser ([...])
|
||||
```
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<br/>
|
||||
|
||||
### Углубленное объяснение
|
||||
|
||||
Механизмы стоящие за построением синхронных и асинхронных стектрейсов в v8 довольно сильно отличаются: синхронные
|
||||
стектрейсы основаны на **стеке** операционной системы на которой запущен Node.js (как и для многих других языков
|
||||
программирования). Во время выполнения асинхронной функции, **стек** операционной системы выталкивает функцию как
|
||||
только та доходит до первого-же `await`. По этому асинхронные стектрейсы представляют собой смесь **стека**
|
||||
операционной системы и **цепочки разрешения отказанного (rejected) промиса**. "Бесплатные асинхронные стектрейсы"
|
||||
реализованны таким образом что **цепочка разрешения промиса** расширяется только когда на промисе исполняется `await`
|
||||
<span>[¹](#1)</span>. По сколько только асинхронные функции могут использовать `await`, синхронные функции
|
||||
всегда будут упущены из асинхронного стектрейса если любая асинхронная операция была исполнена после момента вызова
|
||||
этой синхронной функции <span>[²](#2)</span>
|
||||
|
||||
### Компромисc
|
||||
|
||||
Каждый `await` создает дополнительную микрозадачу (microtask) в цикле событий (event loop), по
|
||||
этому дополнительные `await`-ы в коде создадут определенную дополнительную нагрузку. Тем ни менее,
|
||||
задержки создаваемые сетью и базой данных [несоизмеримо выше](https://colin-scott.github.io/personal_website/research/interactive_latency.html)
|
||||
по этому нагрузка создаваемая дополнительными `await`-ами не является чем-то что стоит принимать во
|
||||
внимание при разработке веб-серверов или интерфейсов командной строки (CLI), разве что для очень
|
||||
горячих участков кода на запрос или команду. По этому убирание `await`-ов из `return await` должно
|
||||
быть одним из последних мест для поиска значимых улучшений производительности приложения и точно не
|
||||
должно выполняться наперед
|
||||
|
||||
### Почему return await раньше считалось анти-паттерном
|
||||
|
||||
Существует ряд [отличных статей](https://jakearchibald.com/2017/await-vs-return-vs-return-await/) объясняющих почему
|
||||
`return await` никогда не должен быть использован за пределами `try` блока и даже
|
||||
[правело ESLint](https://eslint.org/docs/rules/no-return-await) которое такое использование запрещает. Причина
|
||||
заключается в том что с момента когда async/await стали доступны с помощью транспайлеров в Node.js 0.10 (и получил
|
||||
встроенную поддержку с Node.js 7.6) и до момента пока не появились "бесплатные асинхронные стектрейсы", `return await`
|
||||
было абсолютно эквивалентно `await` для любого кода за пределами `try` блока. Для каких-то ES движков это все так-же
|
||||
может оставаться правдой. По этой причине разрешение (resolve) промисов перед возвращением является лучшей практикой
|
||||
для Node.js, а не для EcmaScript в целом
|
||||
|
||||
### Заметки:
|
||||
1. Одной из причин почему асинхронные сетктрейсы имеют столь нетривиальную реализация является требование к
|
||||
стектрейсу быть созданными синхронно, в пределах одного цикла петли событий (event loop) <span id="a1">[¹](#1)</span>
|
||||
2. без `await` в `throwAsync` весь код выполнится в одной фазе петли событий (event loop). Это вырожденный случай
|
||||
когда **стек** операционной системы не успеет опустошиться и стектрейс будет полным даже без явного `await` результата
|
||||
вызова функции. Обычно использование промисов подразумевает исполнение асинхронных операций, а значит части стектрейса
|
||||
все-же будут утрачены
|
||||
3. "Бесплатные асинхронные стектрейсы" не работают для особо сложных потоков промисов, например когда `await`
|
||||
выполняется для одного и того-же промиса в разных местах
|
||||
|
||||
### References:
|
||||
<span id="1">1. </span>[Блогпост о бесплатных асинхронных стектрейсах в v8](https://v8.dev/blog/fast-async)
|
||||
<br>
|
||||
|
||||
<span id="2">2. </span>[Документ о бесплатных асинхронных стектрейсах в v8 с упомянутыми тут деталями реализации](
|
||||
https://docs.google.com/document/d/13Sy_kBIJGP0XT34V1CV3nkWya4TwYx9L3Yv45LdGB6Q/edit
|
||||
)
|
||||
<br>
|
||||
99
sections/errorhandling/shuttingtheprocess.basque.md
Normal file
99
sections/errorhandling/shuttingtheprocess.basque.md
Normal file
@ -0,0 +1,99 @@
|
||||
# Irten prozesutik elegantziarekin kanpoko norbait iristen denean hirira
|
||||
|
||||
### Azalpen paragrafoa
|
||||
|
||||
Zure kodearen lekuren batean, erroreren bat gertatzen denean erroreen kudeaketa objektuaren ardura da erabakitzea nola jokatu, eta, errorea konfiantzazkoa bada, nahikoa izango da erregistro fitxategian idaztea; errorea operazionala bada, berriz, irakurri azalpen osatuagoa #3 jarraibide egokian). Gauzak okertzen dira errorea ezezaguna denean, horrek osagairen bat egoera txarrean dagoela eta hurrengo eskaera guztiek huts egiteko aukera handia dutela esan nahi du eta. Adibidez, eman dezagun, singleton bat edukita, token batek salbuespen bat igorri duela eta ondoren bere egoera galdu duen zerbitzu batekin arazoa duela; hortik aurrera ustekabean joka dezake eta eskaera guztiek huts egitea eragin. Egoera horren aurrean, prozesua gelditu eta 'Berrekite tresna' erabili (Forever, PM2, etab. bezalakoak) egoera garbi batekin berriz hasteko.
|
||||
|
||||
### Kode adibidea: huts eragin ala ez erabakitzen
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
// Garatzaileek operazio erroreak errorea.operazioErroreaDa=true zehazten dutela ziurtzat joz, irakur ezazu #3 jarraibide egokia
|
||||
process.on('uncaughtException', (errorea) => {
|
||||
erroreKudeaketa.kudeatzailea.kudeatuErrorea(errorea);
|
||||
if(!erroreKudeaketa.kudeatzailea.erroreFidagarriaDa(errorea))
|
||||
process.exit(1)
|
||||
});
|
||||
|
||||
// errore kudeatzaile zentralizatuak errore-kudeaketa logika kapsulatzen du
|
||||
function erroreKudeatzailea() {
|
||||
this.kudeatuErrorea = (errorea) => {
|
||||
return logger.erroreaErregistratu(errorea)
|
||||
.then(kritikoaBadaAdministrariariPostaElektronikoaBidali)
|
||||
.then(kritikoaBadaOperazioZerrendanGorde)
|
||||
.then(erabakiIaOperazioErroreaDen);
|
||||
}
|
||||
|
||||
this.erroreFidagarriaDa = (errorea) => {
|
||||
return errorea.operazioErroreaDa;
|
||||
}
|
||||
}
|
||||
```
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
// Garatzaileek operazio erroreak errorea.operazioErroreaDa=true zehazten dutela ziurtzat joz, irakur ezazu #3 jarraibide egokia
|
||||
process.on('uncaughtException', (errorea: Error) => {
|
||||
erroreKudeaketa.kudeatzailea.kudeatuErrorea(errorea);
|
||||
if(!erroreKudeaketa.kudeatzailea.erroreFidagarriaDa(errorea))
|
||||
process.exit(1)
|
||||
});
|
||||
|
||||
// Nodeko Erroretik datorren errore objektu zentralizatua
|
||||
export class AppErrorea extends Error {
|
||||
public readonly operazioErroreaDa: boolean;
|
||||
|
||||
constructor(deskribapena: string, operazioErroreaDa: boolean) {
|
||||
super(deskribapena);
|
||||
Object.setPrototypeOf(this, new.target.prototype); // prototipo katea berreskuratu
|
||||
this.operazioErroreaDa = operazioErroreaDa;
|
||||
Error.captureStackTrace(this);
|
||||
}
|
||||
}
|
||||
|
||||
// errore kudeatzaile zentralizatuak errore-kudeaketa logika kapsulatzen du
|
||||
class ErroreKudeatzailea {
|
||||
public async kudeatuErrorea(errorea: Error): Promise<void> {
|
||||
await logger.erroreaErregistratu(errorea);
|
||||
await kritikoaBadaAdministrariariPostaElektronikoaBidali();
|
||||
await kritikoaBadaOperazioZerrendanGorde();
|
||||
await erabakiIaOperazioErroreaDen();
|
||||
};
|
||||
|
||||
public erroreFidagarriaDa(errorea: Error) {
|
||||
if (errorea instanceof AppErrorea) {
|
||||
return errorea.operazioErroreaDa;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export const kudeatzailea = new ErroreKudeatzailea();
|
||||
```
|
||||
</details>
|
||||
|
||||
### Blogeko aipua: "Irtenbiderik hoberena huts egitea da"
|
||||
|
||||
Joyent blogetik hartua
|
||||
|
||||
> …Programatzaileen erroreak konpontzeko modurik hoberena berehala krak egitea da. Programaren batek huts eginez gero, berrabiarazle bat erabiliz exekutatu beharko zenuke, automatikoki berrabiaraziko baitu. Berrabiarazlea dagoenean, huts egitea da programa fidagarria berreskuratzeko biderik azkarrena programatzailearen errore iragankor baten aurrean ...
|
||||
|
||||
### Blogeko aipua: "Errore kudeaketaren inguruko hiru ideia eskola daude"
|
||||
|
||||
JS Recipes blogetik hartua
|
||||
|
||||
> …Errore kudeaketaren inguruko hiru ideia eskola nagusi daude:
|
||||
1. Utzi aplikazioari huts egiten eta ondoren berrabiarazi
|
||||
2. Errore posible guztiak kudeatu eta inoiz ez huts egin
|
||||
3. Bien arteko planteamendu bat
|
||||
|
||||
### Blogeko aipua: "Ez dago modu segururik irteteko zehaztugabeko egoera hauskorrik sortu gabe"
|
||||
|
||||
Node.js dokumentazio ofizialetik hartua
|
||||
|
||||
> …JavaScripten lanak nola exekutatzen diren kontuan izanda, ez dago ia inoiz lan bati ziurtasunez jarraipena emateko biderik utzitako puntuan hasita, erreferentziak galdu gabe edota bestelako zehaztugabeko egoera hauskorrik sortu gabe. Jaurtitako errore bati erantzuteko modurik seguruena prozesua itzaltzea da. Jakina, web zerbitzari arruntetan, konekxio ugari eduki ahal dituzu irekita, eta ez da zentzuzkoa tupustean haiek ixtea beste batek eragindako errore batengatik. Planteamendu hoberena da bidaltzea errore erantzun bat errorea bidali duen eskariari, besteei beren atazak bukatzeko denbora utziz, eta eskari berriei kasu egiteari uztea prozesu horretan.
|
||||
94
sections/errorhandling/testingerrorflows.basque.md
Normal file
94
sections/errorhandling/testingerrorflows.basque.md
Normal file
@ -0,0 +1,94 @@
|
||||
# Testeatu erroreen fluxua zure test framework gustukoena erabiliz
|
||||
|
||||
### Azalpen paragrafoa
|
||||
|
||||
Bide ‘alaiak’ probatzea ez da hutsegiteak probatzea baino hobea. Probako kodeen estaldura ona da salbuespenezko bideak probatzeko. Bestela, ez dago inolako konfidantzarik salbuespenak zuzen kudeatuta dauden. Unitateen azterketa esparru guztiek, [Mocha](https://mochajs.org/) edo [Chai](http://chaijs.com/) bezala, onartzen dituzte salbuespen probak (kode adibideak beherago). Gogaikarria iruditzen bazaizu funtzio eta salbuespen bakoitza probatzea, REST APIen HTTP erroreak bakarrik probatzea erabaki zenezake.
|
||||
|
||||
|
||||
### Kode adibidea: ziurtatu salbuespen egokia jaurtitzen dela Mocha eta Chai erabiliz
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
describe("Facebooken txata", () => {
|
||||
it("Jakinarazi txateko mezu berria iristean", () => {
|
||||
const txatZerbitzua = new txatZerbitzua();
|
||||
txatZerbitzua.parteHartzaileak = eskuratuDeskonektatutakoParteHartzaileak();
|
||||
expect(txatZerbitzua.mezuaBidali.bind({ mezua: "Aupa" })).to.throw(
|
||||
KonexioErrorea
|
||||
);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
describe("Facebooken txata", () => {
|
||||
it("Jakinarazi txateko mezu berria iristean", () => {
|
||||
const txatZerbitzua = new txatZerbitzua();
|
||||
txatZerbitzua.parteHartzaileak = eskuratuDeskonektatutakoParteHartzaileak();
|
||||
expect(txatZerbitzua.mezuaBidali.bind({ mezua: "Aupa" })).to.throw(
|
||||
KonexioErrorea
|
||||
);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Kodearen adibidea: APIak HTTP errore kode zuzena bueltatzen duela ziurtatu
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
it("Facebookeko talde berria sortu", () => {
|
||||
const taldeOkerrarenInformazioa = {};
|
||||
return httpRequest({
|
||||
method: "POST",
|
||||
uri: "facebook.com/api/groups",
|
||||
resolveWithFullResponse: true,
|
||||
body: taldeOkerrarenInformazioa,
|
||||
json: true,
|
||||
})
|
||||
.then((response) => {
|
||||
expect.fail(
|
||||
"kodea bloke honetan exekutatu nahi bagenu, goiko operazioan errorerik ez da izan"
|
||||
);
|
||||
})
|
||||
.catch((response) => {
|
||||
expect(400).to.equal(response.statusCode);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
it("Facebookeko talde berria sortu", async () => {
|
||||
let taldeOkerrarenInformazioa = {};
|
||||
try {
|
||||
const response = await httpRequest({
|
||||
method: "POST",
|
||||
uri: "facebook.com/api/groups",
|
||||
resolveWithFullResponse: true,
|
||||
body: taldeOkerrarenInformazioa,
|
||||
json: true,
|
||||
});
|
||||
// kodea bloke honetan exekutatu nahi bagenu, goiko operazioan errorerik ez da izan
|
||||
expect.fail("Eskaerak huts egin behar izango luke");
|
||||
} catch (response) {
|
||||
expect(400).to.equal(response.statusCode);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
</details>
|
||||
43
sections/errorhandling/usematurelogger.basque.md
Normal file
43
sections/errorhandling/usematurelogger.basque.md
Normal file
@ -0,0 +1,43 @@
|
||||
# Erabili erregistratze tresna heldu bat erroreen ikusgaitasuna handitzeko
|
||||
|
||||
### Azalpen paragrafoa
|
||||
|
||||
|
||||
Gustuko dugu console.log, baina [Pino][pino] bezalako erregistratzaile tresna ospetsu eta iraunkorra (errendimenduan zentratutako aukera berriagoa) ezinbestekoa da proiektu serioetarako. Errendimendu handiko erregistratze tresnek erroreak eta arazo posibleak identifikatzen laguntzen dute. Erregistratze aholkuen artean:
|
||||
|
||||
1. Maiz erregistratu maila ezberdinak erabiliz (debug, info, error)
|
||||
2. Erregistratzerako orduan, eman testuinguruaren informazioa JSON objektu eran
|
||||
3. Monitorizatu erregistro kontsultak API batekin (erregistro sistema ezberdinetarako erabilgarria) edota erregistro ikustailearen software batekin
|
||||
4. Erakutsi erregistroen informazioa [Splunk][splunk] bezalako operazio inteligentzia tresnekin
|
||||
|
||||
[pino]: https://www.npmjs.com/package/pino
|
||||
[splunk]: https://www.splunk.com/
|
||||
|
||||
### Kode adibidea
|
||||
|
||||
```JavaScript
|
||||
const pino = require('pino');
|
||||
|
||||
// zure erregistro objektu zentralizatua
|
||||
const erregistratzailea = pino();
|
||||
|
||||
// erregistratzailea erabiltzen duen zure kode propioa
|
||||
erregistratzailea.info({ anything: 'Hau metadatua da' }, 'Frogatu Erregistro Mezua %s parametroren batekin', 'parametroren bat');
|
||||
```
|
||||
|
||||
### Blogeko aipua: "Erregistratzailearen betebeharrak"
|
||||
|
||||
StrongLoop blogetik hartua ("Winston eta Bunyanen Node.js Erregistratzaile sistemak konparatzen" Alex Corbatcheven eskutik, 2014ko ekainaren 24a):
|
||||
|
||||
> Identifika ditzagun betebehar gutxi batzuk (erregistratzaile batentzat):
|
||||
>
|
||||
> 1. Denboran seilatu erregistro ilara bakoitza. Nahiko argi dago, erregistroko sarrera bakoitza noiz gertatu den esateko gai izan behar duzu
|
||||
> 2. Erregistro formatua ulergarria izan behar da bai gizakientzat eta baita makinentzat ere
|
||||
> 3. Korronte ezberdin ugari onartu behar ditu. Adibidez, errore erregistroak fitxategi batean idazten ari den unean errorereb bat atzemanez gero, fitxategi beraren barruan idatzi, errorearen fitxategian ere idatzi, eta posta elektronikoa bidali, dena aldi berean, egiteko aukera eman behar du
|
||||
|
||||
### Non dago Winston?
|
||||
|
||||
Zergatik ohiko faboritoak (adibidez, Winston) ez dauden aholkatutako jardunbide
|
||||
onenen egungo zerrendan jakiteko, begiratu [#684][#684]an
|
||||
|
||||
[#684]: https://github.com/goldbergyoni/nodebestpractices/issues/684
|
||||
@ -1,50 +1,42 @@
|
||||
# Use a mature logger to increase errors visibility
|
||||
# Use a mature logger to increase error visibility
|
||||
|
||||
### One Paragraph Explainer
|
||||
|
||||
We all love console.log but obviously, a reputable and persistent logger like [Winston][winston] (highly popular) or [Pino][pino] (the new kid in town which is focused on performance) is mandatory for serious projects. A set of practices and tools will help to reason about errors much quicker – (1) log frequently using different levels (debug, info, error), (2) when logging, provide contextual information as JSON objects, see example below. (3) Watch and filter logs using a log querying API (built-in in most loggers) or a log viewer software. (4) Expose and curate log statement for the operation team using operational intelligence tools like Splunk.
|
||||
We love console.log but a reputable and persistent logger like [Pino][pino] (a newer option focused on performance) is mandatory for serious projects.
|
||||
High-performance logging tools help identify errors and possible issues. Logging recommendations include:
|
||||
|
||||
1. Log frequently using different levels (debug, info, error).
|
||||
2. When logging, provide contextual information as JSON objects.
|
||||
3. Monitor and filter logs with a log querying API (built-in to many loggers) or log viewer software.
|
||||
4. Expose and curate log statements with operational intelligence tools such as [Splunk][splunk].
|
||||
|
||||
[winston]: https://www.npmjs.com/package/winston
|
||||
[pino]: https://www.npmjs.com/package/pino
|
||||
[splunk]: https://www.splunk.com/
|
||||
|
||||
### Code Example – Winston Logger in action
|
||||
### Code Example
|
||||
|
||||
```JavaScript
|
||||
const pino = require('pino');
|
||||
|
||||
```javascript
|
||||
// your centralized logger object
|
||||
const logger = new winston.Logger({
|
||||
level: 'info',
|
||||
transports: [
|
||||
new (winston.transports.Console)()
|
||||
]
|
||||
});
|
||||
const logger = pino();
|
||||
|
||||
// custom code somewhere using the logger
|
||||
logger.log('info', 'Test Log Message with some parameter %s', 'some parameter', { anything: 'This is metadata' });
|
||||
```
|
||||
|
||||
### Code Example – Querying the log folder (searching for entries)
|
||||
|
||||
```javascript
|
||||
const options = {
|
||||
from: Date.now() - 24 * 60 * 60 * 1000,
|
||||
until: new Date(),
|
||||
limit: 10,
|
||||
start: 0,
|
||||
order: 'desc',
|
||||
fields: ['message']
|
||||
};
|
||||
|
||||
// Find items logged between today and yesterday.
|
||||
winston.query(options, (err, results) => {
|
||||
// execute callback with results
|
||||
});
|
||||
logger.info({ anything: 'This is metadata' }, 'Test Log Message with some parameter %s', 'some parameter');
|
||||
```
|
||||
|
||||
### Blog Quote: "Logger Requirements"
|
||||
|
||||
From the blog Strong Loop
|
||||
From the StrongLoop blog ("Comparing Winston and Bunyan Node.js Logging" by Alex Corbatchev, Jun 24, 2014):
|
||||
|
||||
> Let's identify a few requirements (for a logger):
|
||||
> 1. Timestamp each log line. This one is pretty self-explanatory – you should be able to tell when each log entry occurred.
|
||||
> 2. Logging format should be easily digestible by humans as well as machines.
|
||||
> 3. Allows for multiple configurable destination streams. For example, you might be writing trace logs to one file but when an error is encountered, write to the same file, then into error file and send an email at the same time.
|
||||
|
||||
### Where's Winston?
|
||||
|
||||
For more information on why traditional favorites (e.g., Winston) may not be included in the current list of recommended best practices, please see [#684][#684].
|
||||
|
||||
[#684]: https://github.com/goldbergyoni/nodebestpractices/issues/684
|
||||
|
||||
> Lets identify a few requirements (for a logger):
|
||||
1. Timestamp each log line. This one is pretty self-explanatory – you should be able to tell when each log entry occurred.
|
||||
2. Logging format should be easily digestible by humans as well as machines.
|
||||
3. Allows for multiple configurable destination streams. For example, you might be writing trace logs to one file but when an error is encountered, write to the same file, then into error file and send an email at the same time…
|
||||
|
||||
136
sections/errorhandling/useonlythebuiltinerror.basque.md
Normal file
136
sections/errorhandling/useonlythebuiltinerror.basque.md
Normal file
@ -0,0 +1,136 @@
|
||||
# Erabili soilik “Errorea” objektu kapsulatua
|
||||
|
||||
### Azalpen paragrafoa
|
||||
|
||||
JavaScriptek berezko permisibitatea du, eta, bere kode fluxuaren aukera ugariarekin (adibidez EventEmitter, Callbackak, Promesak ...), garatzaileek erroreak kudeatzeko modu anitzak edukitzea eragiten du: batzuek stringak erabiltzen dituzte, besteek beren mota pertsonalizatuak zehazten dituzte. Node.jsen "Errorea" objektu kapsulatua erabiltzeak zure kodearen eta bestelako liburutegien arteko uniformetasuna gordetzen laguntzen du, eta gainera StracTracea bezalako informazio esanguratsua gordetzen du. Salbuespen bat jaurtitzean, jarraibide egokia da errorearen izena edo erlazionatutako HTTP errore kodea bezalako testuinguru ezaugarriekin osatzea. Uniformetasun eta praktika hau lortzeko, saiatu "Errorea" objektua beharrezko ezaugarriekin osatzen, baina kontu izan gehiegitan ez egiten. Orokorrean ideia ona da "Errorea" objektu kapsulatua behin bakarrik osatzea AppErrore batekin aplikazioaren maila guztietako erroreentzat, eta beharrezko duzun informazioa argumentu gisa pasatuz errore klase ezberdinak ezberdintzeko. Ez da beharrezkoa "Errorea" objektua askotan osatzea (errore kasu bakoitzerako behin, adibidez DbError, HttpError...). Begiratu ondorengo kode adibideak
|
||||
|
||||
### Kode adibidea: era zuzenean egin
|
||||
|
||||
```javascript
|
||||
// ohizko funtzio batean Error objektua jaurti, sinkronoa dela edo asinkronoa dela (sync async)
|
||||
if (!gehitzekoProduktua)
|
||||
throw new Error("Nola gehi dezaket produktu bat baliorik ez duenean?");
|
||||
|
||||
// Error objektua jaurti EventEmitteretik
|
||||
const myEmitter = new MyEmitter();
|
||||
nireEmitter.emit("error", new Error("whoops!"));
|
||||
|
||||
// Error objektua jaurti Promesa batetik
|
||||
const gehituProduktua = async (gehitzekoProduktua) => {
|
||||
try {
|
||||
const existitzenDenProduktua = await DAL.eskuratuProduktua(
|
||||
gehitzekoProduktua.id
|
||||
);
|
||||
if (existitzenDenProduktua !== null) {
|
||||
throw new Error("Produktua iada existitzen da!");
|
||||
}
|
||||
} catch (err) {
|
||||
// ...
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Anti jarraibidearen kode adibidea
|
||||
|
||||
```javascript
|
||||
// string baten jaurtiketak edozein pila informazio eta datu ezaugarri garrantzitsu falta ditu
|
||||
if (!gehitzekoProduktua)
|
||||
throw "Nola gehi dezaket produktu bat baliorik ez duenean?";
|
||||
```
|
||||
|
||||
### Kode adibidea: oraindik ere era zuzenagoan egin
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
// Noderen Error objektutik eratortzen den errore objektu zentralizatua
|
||||
function AppErrorea(izena, httpKodea, deskribapena, funtzionatzenDu) {
|
||||
Error.call(this);
|
||||
Error.captureStackTrace(this);
|
||||
this.izena = izena;
|
||||
//...hemen zehaztuta beste ezaugarri batzuk
|
||||
}
|
||||
|
||||
AppErrorea.prototype = Object.create(Error.prototype);
|
||||
AppErrorea.prototype.constructor = AppErrorea;
|
||||
|
||||
module.exports.AppErrorea = AppErrorea;
|
||||
|
||||
// erabiltzailea exzepzio bat jaurtitzen
|
||||
if (erabiltzailea == null)
|
||||
throw new AppErrorea(
|
||||
commonErrors.resourceNotFound,
|
||||
commonHTTPErrors.notFound,
|
||||
"azalpen osatuagoa",
|
||||
true
|
||||
);
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
// Noderen Error objektutik eratortzen den errore objektu zentralizatua
|
||||
export class AppErrorea extends Error {
|
||||
public readonly izena: string;
|
||||
public readonly httpKodea: HttpCode;
|
||||
public readonly funtzionatzenDu: boolean;
|
||||
|
||||
constructor(
|
||||
izena: string,
|
||||
httpKodea: HttpCode,
|
||||
deskribapena: string,
|
||||
funtzionatzenDu: boolean
|
||||
) {
|
||||
super(deskribapena);
|
||||
|
||||
Object.setPrototypeOf(this, new.target.prototype); // prototipo katea berrezarri
|
||||
|
||||
this.izena = izena;
|
||||
this.httpKodea = httpKodea;
|
||||
this.funtzionatzenDu = funtzionatzenDu;
|
||||
|
||||
Error.captureStackTrace(this);
|
||||
}
|
||||
}
|
||||
|
||||
// erabiltzailea exzepzio bat jaurtitzen
|
||||
if (erabiltzailea == null)
|
||||
throw new AppErrorea(
|
||||
commonErrors.resourceNotFound,
|
||||
commonHTTPErrors.notFound,
|
||||
"azalpen osatuagoa",
|
||||
true
|
||||
);
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
_`Object.setPrototypeOf`ri buruzko azalpena Typescripten: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#support-for-newtarget_
|
||||
|
||||
### Blogeko aipua: "Ez diot interesik ikusten mota ezberdin ugari edukitzeari"
|
||||
|
||||
Ben Nadel blogeko “Node.js errore objektua” 5 hitz gakori esker sailkatua
|
||||
|
||||
> …”Nik neuk, ez diot interesik ikusten errore objektu klase ezberdin ugari edukitzeari [bakarra edukitzearekin alderatuz]. Ez dirudi JavaScriptek, lengoaia gisa, eraikitzailez oinarritutako errore harrapaketa hornitzen duenik. Horrela, objektu baten ezaugarriak bereizteak Eraikitzaile klaseak bereiztea baino errazagoa dirudi…
|
||||
|
||||
### Blogeko aipua: "String bat ez da errore bat"
|
||||
|
||||
devthought.com blogeko “Node.js errore objektua” 6 hitz gakori esker sailkatua
|
||||
|
||||
> …String baten ordez errore bat pasatzeak moduluen arteko elkarreragintasuna murrizten du. instanceof errore egiaztapen arrakastatsuak izan litezken kontratuak apurtzen ditu APIekin. Ikusiko dugun bezala, errore objektuek, eraikitzaileari pasatutako mezua kontserbatzeaz gain, Javascript motore modernoetan ezaugarri interesgarriak dituzte…
|
||||
|
||||
### Blogeko aipua: "Erroretik jaraunsteak ez du balio askorik gehitzen"
|
||||
|
||||
machadogj blogetik hartua
|
||||
|
||||
> …Errore klasea jaraunsteko erraza ez izatea arazo bat da. Noski, klasea jaraunts dezakezu eta zure HttpError, DbError, etab. bezalako Error klase propioak sortu. Hala ere, horrek denbora eskatzen du, eta ez du balio askorik gehitzen [AppError batentzat behin bakarrik jaraunsteaz alderatuz], baldin eta klaseekin zerbait egiten ez bazabiltza. Batzuetan, soilik mezu bat gehitu nahi duzu eta barruko errorea mantendu; beste batzuetan, ordea, errorea parametroekin edo bestelako informazioekin osatu nahi zenezake…
|
||||
|
||||
### Blogeko aipua: "Node.jsek jaurtitako JavaScript eta System errore guztiak "Error" objektutik datoz"
|
||||
|
||||
Node.js dokumentazio ofizialetik hartua
|
||||
|
||||
> …Node.jsek jaurtitako JavaScript eta System errore guztiak JavaScripten "Error" klase estandarretik datoz edo "Error" objektuaren instantziak dira, eta gutxienez horrelako ezaugarri erabilgarriak hornitzea bermatzen dute. JavaScript Error objektu generiko bat da, errorea zergatik gertatu den inolako berariazko baldintzarik adierazten ez duena. Error objektuek "pila aztarna" bat atzematen dute, Error instantziatua izan den kodearen lekua zehaztuz, eta errorearen testu deskribapena eduki dezakete. Node.jsek sortutako errore guztiak, System eta JavaScript erroreak barne, Error klasetik eratorritakoak edo Error motaren instantziak izango dira…
|
||||
@ -1,10 +1,10 @@
|
||||
# Use only the built-in Error object
|
||||
# 내장된 Error 객체만 사용하라
|
||||
|
||||
### One Paragraph Explainer
|
||||
### 한문단 설명
|
||||
|
||||
The permissive nature of JS along with its variety code-flow options (e.g. EventEmitter, Callbacks, Promises, etc) pushes to great variance in how developers raise errors – some use strings, other define their own custom types. Using Node.js built-in Error object helps to keep uniformity within your code and with 3rd party libraries, it also preserves significant information like the StackTrace. When raising the exception, it’s usually a good practice to fill it with additional contextual properties like the error name and the associated HTTP error code. To achieve this uniformity and practices, consider extending the Error object with additional properties, see code example below
|
||||
다양한 코드 흐름 옵션(예:EventEmitter, Callbacks, Promises 등)과 함께 JS의 허용 가능한 특성은 개발자가 오류를 발생시키는 방법에 큰 차이를 둔다. – 일부 개발자들은 문자열을 사용하고, 일부는 그들만의 커스텀 타입을 정의한다. Node.js 내장 Error 객체를 사용하면 당신의 코드와 제 3자 라이브러리의 균일성을 유지할 수 있도록 도와주며, 또한 스택정보(StrackTrace)와 같은 중요한 정보도 보존할 수 있다. 예외가 발생할 때, 일반적으로 오류 이름이나 관련 HTTP 오류 코드같은 상황별로 추가적인 속성으로 채우는 것이 좋은 방법이다. 이 균일성과 관행을 얻을려면, Error 객체를 추가 속성으로 확장하라, 아래 코드 예 참조
|
||||
|
||||
### Code Example – doing it right
|
||||
### 코드 예시 – 제대로 하기
|
||||
|
||||
```javascript
|
||||
// throwing an Error from typical function, whether sync or async
|
||||
@ -28,7 +28,7 @@ const addProduct = async (productToAdd) => {
|
||||
}
|
||||
```
|
||||
|
||||
### Code example – Anti Pattern
|
||||
### 코드 예시 - 좋지않은 패턴
|
||||
|
||||
```javascript
|
||||
// throwing a string lacks any stack trace information and other important data properties
|
||||
@ -36,7 +36,7 @@ if(!productToAdd)
|
||||
throw ("How can I add new product when no value provided?");
|
||||
```
|
||||
|
||||
### Code example – doing it even better
|
||||
### 코드 예시 - 훨씬 더 좋다
|
||||
|
||||
```javascript
|
||||
// centralized error object that derives from Node’s Error
|
||||
@ -57,26 +57,26 @@ if(user == null)
|
||||
throw new AppError(commonErrors.resourceNotFound, commonHTTPErrors.notFound, "further explanation", true)
|
||||
```
|
||||
|
||||
### Blog Quote: "I don’t see the value in having lots of different types"
|
||||
### 블로그 인용: "여러 가지 유형이 있다는 것은 가치가 없다고 본다"
|
||||
|
||||
From the blog, Ben Nadel ranked 5 for the keywords “Node.js error object”
|
||||
Ben Nadel 블로그에서 "Node.js error 객체" 키워드 5위에 위치했다.
|
||||
|
||||
>…”Personally, I don’t see the value in having lots of different types of error objects – JavaScript, as a language, doesn’t seem to cater to Constructor-based error-catching. As such, differentiating on an object property seems far easier than differentiating on a Constructor type…
|
||||
>…”개인적으로, 여러 가지 유형이 있다는 것은 가치가 없다고 본다 – 언어로서의 자바스크립트는 생성자 기반의 오류 파악에 적합하지 않은 것 같다. 따라서, 객체 속성에서 구별하는 것이 생성자 유형에서 구분하는 것보다 훨씬 쉬운 것 같다…
|
||||
|
||||
### Blog Quote: "A string is not an error"
|
||||
### 블로그 인용: "문자열은 오류가 아니다"
|
||||
|
||||
From the blog, devthought.com ranked 6 for the keywords “Node.js error object”
|
||||
devthought.com 블로그에서 "Node.js error 객체" 키워드 6위에 위치했다.
|
||||
|
||||
> …passing a string instead of an error results in reduced interoperability between modules. It breaks contracts with APIs that might be performing `instanceof` Error checks, or that want to know more about the error. Error objects, as we’ll see, have very interesting properties in modern JavaScript engines besides holding the message passed to the constructor…
|
||||
> …오류 대신 문자열을 전달함으로써 모듈 간의 상호운용성이 줄어들었다. 문자열을 사용하면 `instanceof` 에러로 검사하는 API 계약을 깨뜨리는 데다가 오류의 자세한 정보도 알기 어렵다. 뒤에서 설명하겠지만, 최신 자바스크립트 엔진의 Error 객체에는 유용한 속성을 많이 있으며 생성자에 전달된 메시지도 포함된다…
|
||||
|
||||
### Blog Quote: "Inheriting from Error doesn’t add too much value"
|
||||
### 블로그 인용: "에러로 부터 상속해도 많은 값을 추가하지 않는다"
|
||||
|
||||
From the blog machadogj
|
||||
machadogj 블로그에서
|
||||
|
||||
> …One problem that I have with the Error class is that is not so simple to extend. Of course, you can inherit the class and create your own Error classes like HttpError, DbError, etc. However, that takes time and doesn’t add too much value unless you are doing something with types. Sometimes, you just want to add a message and keep the inner error, and sometimes you might want to extend the error with parameters, and such…
|
||||
> …Error 클래스와 관련된 한 가지 문제는 확장하기가 그리 간단하지 않다는 것이다. 물론 클래스를 상속하고 HttpError, DbError 등 자신만의 에러 클래스를 만들 수 있다. 그러나, 당신이 타입으로 무엇인가를 하지 않는 한 이것은 시간이 걸리며 많은 값을 추가하지 않는다. 때로 당신은 메시지 추가와 내부 에러를 유지하길 원하고 때로는 매개 변수를 사용하여 에러를 확장하길 원할 것이다, 등등…
|
||||
|
||||
### Blog Quote: "All JavaScript and System errors raised by Node.js inherit from Error"
|
||||
### 블로그 인용: "모든 자바스크립트와 시스템 에러들은 node.js이 상속한 에러로 부터 발생한다"
|
||||
|
||||
From Node.js official documentation
|
||||
Node.js 공식문서에서
|
||||
|
||||
> …All JavaScript and System errors raised by Node.js inherit from, or are instances of, the standard JavaScript Error class and are guaranteed to provide at least the properties available on that class. A generic JavaScript Error object that does not denote any specific circumstance of why the error occurred. Error objects capture a “stack trace” detailing the point in the code at which the Error was instantiated, and may provide a text description of the error. All errors generated by Node.js, including all System and JavaScript errors, will either be instances of or inherit from, the Error class…
|
||||
> …Node.js에 의해 발생된 모든 자바스크립트 및 시스템 에러는 표준 자바스크립트 에러 클래스에서 상속되거나 표준 자바스크립트 에러 클래스의 인스턴스이며 최소한 그 클래스에서 사용할 수 있는 속성을 제공할 수 있도록 보장된다. 에러가 발생한 이유에 대한 특정 상황을 나타내지 않는 일반 자바스크립트 에러 객체. 에러 객체는 에러가 인스턴스화된 코드에서 포인트를 자세히 설명하는 "스택 추적"을 캡처(capture)하며, 에러에 대한 텍스트 설명을 제공할 수도 있다. 모든 시스템과 자바스크립트 에러를 포함한 Node.js에 의해, 생성된 모든 에러는, 에러 클래스의 인스턴스이거나, 상속 받은 것이다.…
|
||||
|
||||
@ -2,20 +2,20 @@
|
||||
|
||||
### Объяснение в один абзац
|
||||
|
||||
Всепозволяющая природа JavaScript наряду с его разнообразием параметров потока кода (например, EventEmitter, Callbacks, Promises и т.д.) приводит к значительному расхождению в том, как разработчики выдают ошибки - некоторые используют строки, другие определяют свои собственные пользовательские типы. Использование встроенного объекта Error в Node.js помогает сохранить единообразие в вашем коде, а с помощью сторонних библиотек он также сохраняет важную информацию, такую как StackTrace. При возникновении исключения обычно рекомендуется заполнить его дополнительными контекстными свойствами, такими как имя ошибки и связанный код ошибки HTTP. Чтобы добиться этого единообразия и практики, рассмотрите возможность расширения объекта Error дополнительными свойствами, см. пример кода ниже.
|
||||
Гибкая природа JavaScript наряду с его разнообразием вариантов потока кода (например, EventEmitter, Callbacks, Promises и т.д.) приводит к значительному расхождению в том, как разработчики выдают ошибки - некоторые используют строки, другие определяют свои собственные пользовательские типы. Использование встроенного объекта Error в Node.js помогает сохранить единообразие в вашем коде, а с помощью сторонних библиотек он также сохраняет важную информацию, такую как StackTrace. При возникновении исключения обычно рекомендуется заполнить его дополнительными контекстными свойствами, такими как имя ошибки и связанный код ошибки HTTP. Чтобы добиться этого единообразия и практики, рассмотрите возможность расширения объекта Error дополнительными свойствами, см. пример кода ниже.
|
||||
|
||||
### Пример кода - делай все правильно
|
||||
|
||||
```javascript
|
||||
// throwing an Error from typical function, whether sync or async
|
||||
// пробрасываем Error из типичной async или sync функции
|
||||
if(!productToAdd)
|
||||
throw new Error('How can I add new product when no value provided?');
|
||||
|
||||
// 'throwing' an Error from EventEmitter
|
||||
// пробрасываем Error из EventEmitter
|
||||
const myEmitter = new MyEmitter();
|
||||
myEmitter.emit('error', new Error('whoops!'));
|
||||
|
||||
// 'throwing' an Error from a Promise
|
||||
// пробрасываем Error из Promise
|
||||
const addProduct = async (productToAdd) => {
|
||||
try {
|
||||
const existingProduct = await DAL.getProduct(productToAdd.id);
|
||||
@ -31,23 +31,23 @@ const addProduct = async (productToAdd) => {
|
||||
### Пример кода - антипаттерн
|
||||
|
||||
```javascript
|
||||
// throwing a string lacks any stack trace information and other important data properties
|
||||
// пробрасывая строку, теряем информацию о stack trace и другие важные параметры
|
||||
if(!productToAdd)
|
||||
throw ('How can I add new product when no value provided?');
|
||||
```
|
||||
|
||||
### Пример кода - делаем это еще лучше
|
||||
### Пример кода - делаем еще лучше
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
// centralized error object that derives from Node’s Error
|
||||
// главные объект ошибки производный от нодовского Error
|
||||
function AppError(name, httpCode, description, isOperational) {
|
||||
Error.call(this);
|
||||
Error.captureStackTrace(this);
|
||||
this.name = name;
|
||||
//...other properties assigned here
|
||||
//... другие параметры тут
|
||||
};
|
||||
|
||||
AppError.prototype = Object.create(Error.prototype);
|
||||
@ -55,7 +55,7 @@ AppError.prototype.constructor = AppError;
|
||||
|
||||
module.exports.AppError = AppError;
|
||||
|
||||
// client throwing an exception
|
||||
// клиент пробрасывает исключение
|
||||
if(user == null)
|
||||
throw new AppError(commonErrors.resourceNotFound, commonHTTPErrors.notFound, 'further explanation', true)
|
||||
```
|
||||
@ -65,7 +65,7 @@ if(user == null)
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
// centralized error object that derives from Node’s Error
|
||||
// главные объект ошибки производный от нодовского Error
|
||||
export class AppError extends Error {
|
||||
public readonly name: string;
|
||||
public readonly httpCode: HttpCode;
|
||||
@ -74,7 +74,7 @@ export class AppError extends Error {
|
||||
constructor(name: string, httpCode: HttpCode, description: string, isOperational: boolean) {
|
||||
super(description);
|
||||
|
||||
Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain
|
||||
Object.setPrototypeOf(this, new.target.prototype); // восстанавливаем цепочку прототипов
|
||||
|
||||
this.name = name;
|
||||
this.httpCode = httpCode;
|
||||
@ -84,7 +84,7 @@ export class AppError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
// client throwing an exception
|
||||
// клиент пробрасывает исключение
|
||||
if(user == null)
|
||||
throw new AppError(commonErrors.resourceNotFound, commonHTTPErrors.notFound, 'further explanation', true)
|
||||
```
|
||||
@ -96,22 +96,22 @@ if(user == null)
|
||||
|
||||
Из блога Бен Надель, занял 5 место по ключевым словам "объект ошибки Node.js"
|
||||
|
||||
> … Лично я не вижу смысла в том, чтобы иметь множество различных типов объектов ошибок - JavaScript, как язык, похоже, не предназначен для поиска ошибок на основе конструктора. Таким образом, дифференцирование по свойству объекта кажется гораздо проще, чем по типу Constructor …
|
||||
> … Лично я не вижу смысла в том, чтобы иметь множество различных типов объектов ошибок - JavaScript, как язык, похоже, не предназначен для поиска ошибок на основе конструктора. Таким образом, определение по свойству объекта кажется гораздо проще, чем по типу Constructor …
|
||||
|
||||
### Цитата блога: "Строка не является ошибкой"
|
||||
|
||||
Из блога devthought.com, занял 6 место по ключевым словам "Объект ошибки Node.js"
|
||||
|
||||
> … передача строки вместо ошибки приводит к снижению совместимости между модулями. Он нарушает контракты с API, которые могут выполнять проверки ошибок instanceof или хотят узнать больше об ошибке. Объекты ошибок, как мы увидим, обладают очень интересными свойствами в современных механизмах JavaScript, помимо хранения сообщения, переданного конструктору …
|
||||
> … передача строки вместо ошибки приводит к снижению совместимости между модулями. Это нарушает контракты с API, которые могут выполнять проверки ошибок с помощью instanceof или хотят узнать больше об ошибке. Объекты ошибок, как мы увидим, обладают очень интересными свойствами в современных механизмах JavaScript, помимо хранения сообщения, переданного конструктору …
|
||||
|
||||
### Цитата из блога: "Наследование от ошибки не увеличивает ценность"
|
||||
### Цитата из блога: "Наследование от ошибки не увеличивает их ценность"
|
||||
|
||||
Из блога Machadogj
|
||||
|
||||
> … Одна проблема, которую я имею с классом Error, заключается в том, что его не так просто расширить. Конечно, вы можете наследовать класс и создавать свои собственные классы ошибок, такие как HttpError, DbError и т.д. Однако это занимает время и не добавляет слишком много значения, если вы не делаете что-то с типами. Иногда вам просто нужно добавить сообщение и сохранить внутреннюю ошибку, а иногда вам может понадобиться расширить ошибку с помощью параметров, и так далее …
|
||||
|
||||
### Цитата из блога: "Все ошибки JavaScript и системы, возникающие в Node.js, наследуются от ошибок"
|
||||
### Цитата из блога: "Все ошибки JavaScript и системы, возникающие в Node.js, наследуются от Error"
|
||||
|
||||
Из официальной документации Node.js
|
||||
|
||||
> … Все ошибки JavaScript и System, возникающие в Node.js, наследуются или являются экземплярами стандартного класса JavaScript Error и гарантированно предоставляют как минимум свойства, доступные в этом классе. Общий объект JavaScript Error, который не обозначает каких-либо конкретных обстоятельств, по которым произошла ошибка. Объекты ошибок фиксируют "трассировку стека", детализирующую точку в коде, в которой был создан экземпляр ошибки, и могут предоставлять текстовое описание ошибки. Все ошибки, сгенерированные Node.js, включая все системные ошибки и ошибки JavaScript, будут либо экземплярами класса Error, либо наследоваться от него …
|
||||
> … Все ошибки JavaScript и System, возникающие в Node.js, наследуются или являются экземплярами стандартного класса JavaScript Error и гарантированно предоставляют как минимум свойства, доступные в этом классе. Общий объект JavaScript Error, который не обозначает каких-либо конкретных обстоятельств, по которым произошла ошибка. Объекты ошибок фиксируют "трассировку стека", детализирующую точку в коде, в которой был создан экземпляр ошибки, и могут предоставлять текстовое описание ошибки. Все ошибки, сгенерированные Node.js, включая все системные ошибки и ошибки JavaScript, будут либо экземплярами класса Error, либо наследоваться от него …
|
||||
Reference in New Issue
Block a user