Witaj ponownie w Parku Jurajskim! W poprzednich ćwiczeniach poznaliśmy różne rodzaje błędów występujących w JavaScript oraz podstawy ich obsługi za pomocą
try...catch...finally. Teraz zagłębimy się w tworzenie własnych, niestandardowych klas błędów, które są nieocenione w dużych aplikacjach - takich jak systemy zarządzania parkiem pełnym prehistorycznych gadów.W złożonych systemach, takich jak Park Jurajski, potrzebujemy precyzyjnej kategoryzacji problemów. Nie wystarczy wiedzieć, że "coś poszło nie tak" - musimy wiedzieć dokładnie, co się stało, gdzie, i jak na to zareagować.
Własne klasy błędów pozwalają na:
To jak różnica między ogólnym alarmem w parku a precyzyjnym komunikatem: "Velociraptory wydostały się z wybiegu B6, ostatnio widziane zmierzające w kierunku centrum dla zwiedzających".
W JavaScript wszystkie błędy dziedziczą z bazowej klasy
Error. Nasze własne klasy błędów powinny również dziedziczyć z Error lub jednej z jej podklas.1class DinosaurError extends Error {
2 constructor(message) {
3 super(message); // Wywołanie konstruktora klasy nadrzędnej
4 this.name = 'DinosaurError'; // Nadpisanie nazwy błędu
5 }
6}
7
8// Użycie
9try {
10 throw new DinosaurError('Nieoczekiwane zachowanie T-Rexa');
11} catch (error) {
12 console.log(error.name); // 'DinosaurError'
13 console.log(error.message); // 'Nieoczekiwane zachowanie T-Rexa'
14}Największą zaletą własnych klas błędów jest możliwość dodania dodatkowych właściwości z kontekstem:
1class EnclosureBreachError extends Error {
2 constructor(message, dinosaurSpecies, location, dangerLevel) {
3 super(message);
4 this.name = 'EnclosureBreachError';
5 this.dinosaurSpecies = dinosaurSpecies;
6 this.location = location;
7 this.dangerLevel = dangerLevel;
8 this.timestamp = new Date();
9 }
10
11 getEmergencyMessage() {
12 return `UWAGA! ${this.dinosaurSpecies} wydostał się z wybiegu w lokalizacji ${this.location}.
13 Poziom zagrożenia: ${this.dangerLevel}/10.
14 Czas zdarzenia: ${this.timestamp.toLocaleTimeString()}`;
15 }
16}
17
18// Użycie
19try {
20 throw new EnclosureBreachError(
21 'Naruszenie zabezpieczeń wybiegu',
22 'Velociraptor',
23 'Sektor B6',
24 9
25 );
26} catch (error) {
27 if (error instanceof EnclosureBreachError) {
28 console.error(error.getEmergencyMessage());
29
30 // Uruchomienie odpowiednich procedur awaryjnych zależnie od poziomu zagrożenia
31 if (error.dangerLevel >= 8) {
32 evacuateSector(error.location);
33 dispatchSecurityTeam(error.location, error.dinosaurSpecies);
34 }
35 }
36}W dużych aplikacjach, takich jak system zarządzania Parkiem Jurajskim, warto stworzyć hierarchię klas błędów:
1// Bazowa klasa błędu specyficzna dla aplikacji
2class JurassicParkError extends Error {
3 constructor(message) {
4 super(message);
5 this.name = 'JurassicParkError';
6 this.timestamp = new Date();
7 }
8
9 logError() {
10 console.error(`[${this.timestamp.toISOString()}] ${this.name}: ${this.message}`);
11 }
12}
13
14// Błędy związane z dinozaurami
15class DinosaurError extends JurassicParkError {
16 constructor(message, species) {
17 super(message);
18 this.name = 'DinosaurError';
19 this.species = species;
20 }
21}
22
23// Konkretne typy błędów związanych z dinozaurami
24class DinosaurHealthError extends DinosaurError {
25 constructor(message, species, healthIssue, severity) {
26 super(message, species);
27 this.name = 'DinosaurHealthError';
28 this.healthIssue = healthIssue;
29 this.severity = severity;
30 }
31
32 requiresVeterinarian() {
33 return this.severity >= 7;
34 }
35}
36
37class DinosaurBehaviorError extends DinosaurError {
38 constructor(message, species, behavior, dangerLevel) {
39 super(message, species);
40 this.name = 'DinosaurBehaviorError';
41 this.behavior = behavior;
42 this.dangerLevel = dangerLevel;
43 }
44
45 requiresIntervention() {
46 return this.dangerLevel >= 5;
47 }
48}
49
50// Błędy związane z infrastrukturą parku
51class ParkInfrastructureError extends JurassicParkError {
52 constructor(message, systemName, location) {
53 super(message);
54 this.name = 'ParkInfrastructureError';
55 this.systemName = systemName;
56 this.location = location;
57 }
58}
59
60// Konkretne typy błędów infrastruktury
61class PowerSystemError extends ParkInfrastructureError {
62 constructor(message, location, affectedSystems) {
63 super(message, 'PowerSystem', location);
64 this.name = 'PowerSystemError';
65 this.affectedSystems = affectedSystems;
66 }
67
68 requiresBackupPower() {
69 return this.affectedSystems.includes('SecurityFences');
70 }
71}Taka hierarchia pozwala na precyzyjną obsługę różnych typów błędów:
1async function monitorParkSystems() {
2 try {
3 await checkDinosaurHealth();
4 await checkEnclosureSecurity();
5 await checkPowerSystems();
6 } catch (error) {
7 // Logowanie wszystkich błędów
8 console.error(`[${new Date().toISOString()}] Error:`, error);
9
10 // Różne reakcje w zależności od typu błędu
11 if (error instanceof DinosaurHealthError) {
12 if (error.requiresVeterinarian()) {
13 await dispatchVeterinarianTeam(error.species, error.healthIssue, error.severity);
14 } else {
15 await scheduleRoutineCheckup(error.species);
16 }
17 }
18 else if (error instanceof DinosaurBehaviorError) {
19 if (error.requiresIntervention()) {
20 await dispatchBehavioralSpecialist(error.species, error.behavior);
21 if (error.dangerLevel >= 8) {
22 await prepareTransquilizers(error.species);
23 }
24 }
25 }
26 else if (error instanceof PowerSystemError) {
27 await notifyMaintenanceTeam(error.location, error.message);
28 if (error.requiresBackupPower()) {
29 await activateBackupGenerators(error.location);
30 }
31 }
32 else if (error instanceof JurassicParkError) {
33 // Ogólna obsługa dla wszystkich błędów parku
34 await logToSecuritySystem(error);
35 }
36 else {
37 // Nieznany typ błędu
38 console.error('Nieznany błąd:', error);
39 }
40 }
41}Jeden z problemów z obiektami błędów w JavaScript to ich serializacja. Domyślnie, gdy próbujemy przekonwertować błąd do JSON, tracimy większość informacji:
1const error = new Error('Test error');
2console.log(JSON.stringify(error)); // {} - puste obiekty!Własne klasy błędów mogą rozwiązać ten problem implementując metodę
toJSON:1class SerializableError extends Error {
2 constructor(message) {
3 super(message);
4 this.name = this.constructor.name;
5 }
6
7 toJSON() {
8 return {
9 name: this.name,
10 message: this.message,
11 stack: this.stack,
12 // Dodatkowe właściwości specyficzne dla podklas
13 ...Object.getOwnPropertyNames(this)
14 .filter(prop => !['name', 'message', 'stack'].includes(prop))
15 .reduce((obj, prop) => {
16 obj[prop] = this[prop];
17 return obj;
18 }, {})
19 };
20 }
21}
22
23// Teraz możemy tworzyć serializowalne błędy
24class DinosaurEscapeError extends SerializableError {
25 constructor(message, species, location) {
26 super(message);
27 this.species = species;
28 this.location = location;
29 this.timestamp = new Date();
30 }
31}
32
33const error = new DinosaurEscapeError(
34 'Dinozaur uciekł z wybiegu',
35 'Velociraptor',
36 'Sektor B6'
37);
38
39// Teraz error można poprawnie serializować
40console.log(JSON.stringify(error, null, 2));
41/* Wynik:
42{
43 "name": "DinosaurEscapeError",
44 "message": "Dinozaur uciekł z wybiegu",
45 "stack": "DinosaurEscapeError: Dinozaur uciekł z wybiegu\n at ...",
46 "species": "Velociraptor",
47 "location": "Sektor B6",
48 "timestamp": "2023-05-15T10:30:45.123Z"
49}
50*/Jest to szczególnie przydatne, gdy musimy przesyłać informacje o błędach przez API lub zapisywać je w logach.
Własne klasy błędów świetnie współpracują z asynchronicznym kodem:
1// Klasa błędu specyficzna dla API
2class APIError extends Error {
3 constructor(message, statusCode, endpoint) {
4 super(message);
5 this.name = 'APIError';
6 this.statusCode = statusCode;
7 this.endpoint = endpoint;
8 this.timestamp = new Date();
9 }
10
11 isServerError() {
12 return this.statusCode >= 500;
13 }
14
15 isClientError() {
16 return this.statusCode >= 400 && this.statusCode < 500;
17 }
18
19 isAuthError() {
20 return this.statusCode === 401 || this.statusCode === 403;
21 }
22}
23
24// Funkcja pobierająca dane z API, która używa niestandardowej klasy błędu
25async function fetchDinosaurData(dinoId) {
26 try {
27 const response = await fetch(`https://jurassic-park-api.com/dinosaurs/${dinoId}`);
28
29 if (!response.ok) {
30 throw new APIError(
31 `Błąd podczas pobierania danych o dinozaurze #${dinoId}`,
32 response.status,
33 `/dinosaurs/${dinoId}`
34 );
35 }
36
37 return await response.json();
38 } catch (error) {
39 if (error instanceof APIError) {
40 // Obsługa błędów API
41 if (error.isAuthError()) {
42 await refreshAuthToken();
43 return fetchDinosaurData(dinoId); // Ponowna próba po odświeżeniu tokenu
44 } else if (error.isServerError()) {
45 console.error('Błąd serwera, próba użycia zapasowego API...');
46 return fetchDinosaurDataFromBackupAPI(dinoId);
47 } else {
48 console.error(`Błąd klienta: ${error.message} (statusCode: ${error.statusCode})`);
49 throw error; // Przekazujemy błąd dalej
50 }
51 } else {
52 // Inny rodzaj błędu (np. sieciowy)
53 console.error('Nieoczekiwany błąd:', error);
54 throw new Error(`Nie udało się pobrać danych o dinozaurze #${dinoId}: ${error.message}`);
55 }
56 }
57}Zobaczmy, jak możemy wykorzystać własne klasy błędów w bardziej rozbudowanym przykładzie - systemie raportowania incydentów w Parku Jurajskim:
1// Bazowa klasa błędu dla incydentów
2class IncidentError extends Error {
3 constructor(message, location, severity) {
4 super(message);
5 this.name = 'IncidentError';
6 this.location = location;
7 this.severity = severity; // 1-10
8 this.timestamp = new Date();
9 this.resolved = false;
10 this.resolutionTime = null;
11 }
12
13 markAsResolved() {
14 this.resolved = true;
15 this.resolutionTime = new Date();
16 return this;
17 }
18
19 getIncidentDuration() {
20 if (!this.resolved) return null;
21 return (this.resolutionTime - this.timestamp) / 1000; // w sekundach
22 }
23
24 requiresEvacuation() {
25 return this.severity >= 7;
26 }
27
28 requiresNotification() {
29 return this.severity >= 4;
30 }
31
32 getSummary() {
33 return {
34 type: this.name,
35 message: this.message,
36 location: this.location,
37 severity: this.severity,
38 timestamp: this.timestamp,
39 status: this.resolved ? 'Rozwiązany' : 'Aktywny',
40 resolutionTime: this.resolutionTime
41 };
42 }
43
44 toJSON() {
45 return this.getSummary();
46 }
47}
48
49// Klasy dla różnych typów incydentów
50class DinosaurEscapeIncident extends IncidentError {
51 constructor(message, location, species, count, dangerLevel) {
52 super(message, location, dangerLevel);
53 this.name = 'DinosaurEscapeIncident';
54 this.species = species;
55 this.count = count;
56 this.lastSighting = location;
57 }
58
59 updateSighting(newLocation) {
60 this.lastSighting = newLocation;
61 return this;
62 }
63
64 getSummary() {
65 return {
66 ...super.getSummary(),
67 species: this.species,
68 count: this.count,
69 lastSighting: this.lastSighting
70 };
71 }
72}
73
74class SystemFailureIncident extends IncidentError {
75 constructor(message, location, system, affectedAreas, backupStatus) {
76 // Obliczenie poziomu krytyczności na podstawie systemu i dostępności backupu
77 const severity = SystemFailureIncident.calculateSeverity(system, backupStatus);
78
79 super(message, location, severity);
80 this.name = 'SystemFailureIncident';
81 this.system = system;
82 this.affectedAreas = affectedAreas;
83 this.backupStatus = backupStatus;
84 }
85
86 static calculateSeverity(system, backupStatus) {
87 const systemCriticality = {
88 'electric_fences': 10,
89 'security_doors': 9,
90 'surveillance': 7,
91 'climate_control': 6,
92 'guest_services': 3
93 };
94
95 // Jeśli backup działa, zmniejsz poziom krytyczności
96 const baseSeverity = systemCriticality[system] || 5;
97 return backupStatus === 'operational' ? Math.max(3, baseSeverity - 3) : baseSeverity;
98 }
99
100 requiresMaintenanceTeam() {
101 return true;
102 }
103
104 requiresEmergencyPower() {
105 return this.system === 'electric_fences' || this.system === 'security_doors';
106 }
107
108 getSummary() {
109 return {
110 ...super.getSummary(),
111 system: this.system,
112 affectedAreas: this.affectedAreas,
113 backupStatus: this.backupStatus,
114 requiresEmergencyPower: this.requiresEmergencyPower()
115 };
116 }
117}
118
119class VisitorIncident extends IncidentError {
120 constructor(message, location, visitorCount, injuryLevel, medicalStatus) {
121 // Obliczenie poziomu krytyczności na podstawie liczby gości i poziomu obrażeń
122 const severity = VisitorIncident.calculateSeverity(visitorCount, injuryLevel);
123
124 super(message, location, severity);
125 this.name = 'VisitorIncident';
126 this.visitorCount = visitorCount;
127 this.injuryLevel = injuryLevel; // 'none', 'minor', 'moderate', 'severe'
128 this.medicalStatus = medicalStatus; // 'not_required', 'dispatched', 'on_scene', 'evacuating'
129 }
130
131 static calculateSeverity(visitorCount, injuryLevel) {
132 const injurySeverity = {
133 'none': 1,
134 'minor': 3,
135 'moderate': 6,
136 'severe': 9
137 };
138
139 // Zwiększ poziom krytyczności dla większej liczby gości
140 const baseSeverity = injurySeverity[injuryLevel] || 5;
141 const visitorFactor = visitorCount > 10 ? 2 : visitorCount > 3 ? 1 : 0;
142
143 return Math.min(10, baseSeverity + visitorFactor);
144 }
145
146 requiresMedicalTeam() {
147 return this.injuryLevel !== 'none';
148 }
149
150 updateMedicalStatus(newStatus) {
151 this.medicalStatus = newStatus;
152
153 // Jeśli pomoc medyczna jest na miejscu i sytuacja nie jest krytyczna,
154 // możemy zmniejszyć poziom krytyczności
155 if (newStatus === 'on_scene' && this.injuryLevel !== 'severe') {
156 this.severity = Math.max(2, this.severity - 2);
157 }
158
159 return this;
160 }
161
162 getSummary() {
163 return {
164 ...super.getSummary(),
165 visitorCount: this.visitorCount,
166 injuryLevel: this.injuryLevel,
167 medicalStatus: this.medicalStatus,
168 requiresMedicalTeam: this.requiresMedicalTeam()
169 };
170 }
171}
172
173// System zarządzania incydentami
174class IncidentManagementSystem {
175 constructor() {
176 this.activeIncidents = new Map();
177 this.resolvedIncidents = [];
178 this.eventListeners = {
179 'new': [],
180 'update': [],
181 'resolve': []
182 };
183 }
184
185 reportIncident(incident) {
186 if (!(incident instanceof IncidentError)) {
187 throw new TypeError('Można raportować tylko obiekty typu IncidentError');
188 }
189
190 const incidentId = `INC-${Date.now()}-${Math.floor(Math.random() * 1000)}`;
191 this.activeIncidents.set(incidentId, incident);
192
193 // Powiadomienie wszystkich słuchaczy o nowym incydencie
194 this._notifyListeners('new', { id: incidentId, incident });
195
196 // Automatyczne reakcje na incydent
197 this._triggerAutomatedResponses(incidentId, incident);
198
199 return incidentId;
200 }
201
202 updateIncident(incidentId, updateFn) {
203 if (!this.activeIncidents.has(incidentId)) {
204 throw new Error(`Incydent o ID ${incidentId} nie istnieje lub został już rozwiązany`);
205 }
206
207 const incident = this.activeIncidents.get(incidentId);
208 updateFn(incident);
209
210 // Powiadomienie wszystkich słuchaczy o aktualizacji incydentu
211 this._notifyListeners('update', { id: incidentId, incident });
212
213 return incident;
214 }
215
216 resolveIncident(incidentId, resolutionNotes = '') {
217 if (!this.activeIncidents.has(incidentId)) {
218 throw new Error(`Incydent o ID ${incidentId} nie istnieje lub został już rozwiązany`);
219 }
220
221 const incident = this.activeIncidents.get(incidentId);
222 incident.markAsResolved();
223 incident.resolutionNotes = resolutionNotes;
224
225 // Przenieś incydent z aktywnych do rozwiązanych
226 this.activeIncidents.delete(incidentId);
227 this.resolvedIncidents.push({ id: incidentId, incident });
228
229 // Powiadomienie wszystkich słuchaczy o rozwiązaniu incydentu
230 this._notifyListeners('resolve', { id: incidentId, incident });
231
232 return incident;
233 }
234
235 getActiveIncidents() {
236 return Array.from(this.activeIncidents.entries()).map(([id, incident]) => ({
237 id,
238 ...incident.getSummary()
239 }));
240 }
241
242 getIncidentById(incidentId) {
243 if (this.activeIncidents.has(incidentId)) {
244 return {
245 id: incidentId,
246 status: 'active',
247 ...this.activeIncidents.get(incidentId).getSummary()
248 };
249 }
250
251 const resolvedIncident = this.resolvedIncidents.find(inc => inc.id === incidentId);
252 if (resolvedIncident) {
253 return {
254 id: incidentId,
255 status: 'resolved',
256 ...resolvedIncident.incident.getSummary()
257 };
258 }
259
260 return null;
261 }
262
263 addEventListener(event, callback) {
264 if (!this.eventListeners[event]) {
265 throw new Error(`Nieznany typ zdarzenia: ${event}`);
266 }
267
268 this.eventListeners[event].push(callback);
269 return () => this.removeEventListener(event, callback); // Funkcja do usunięcia listenera
270 }
271
272 removeEventListener(event, callback) {
273 if (!this.eventListeners[event]) return false;
274
275 const index = this.eventListeners[event].indexOf(callback);
276 if (index !== -1) {
277 this.eventListeners[event].splice(index, 1);
278 return true;
279 }
280 return false;
281 }
282
283 _notifyListeners(event, data) {
284 if (!this.eventListeners[event]) return;
285
286 for (const listener of this.eventListeners[event]) {
287 try {
288 listener(data);
289 } catch (error) {
290 console.error(`Błąd w listenerze zdarzenia ${event}:`, error);
291 }
292 }
293 }
294
295 _triggerAutomatedResponses(incidentId, incident) {
296 console.log(`Automatyczna reakcja na incydent ${incidentId}:`, incident.name);
297
298 // Różne reakcje w zależności od typu incydentu
299 if (incident instanceof DinosaurEscapeIncident) {
300 if (incident.requiresEvacuation()) {
301 console.log(`EWAKUACJA! Uruchamianie protokołu ewakuacji dla: ${incident.location}`);
302 // evacuateSector(incident.location);
303 }
304
305 console.log(`Wysyłanie zespołu ACU (Asset Containment Unit) do lokalizacji: ${incident.lastSighting}`);
306 // dispatchACUTeam(incident.lastSighting, incident.species, incident.count);
307 }
308
309 else if (incident instanceof SystemFailureIncident) {
310 console.log(`Powiadomienie zespołu technicznego o awarii systemu: ${incident.system}`);
311 // notifyMaintenanceTeam(incident.system, incident.location);
312
313 if (incident.requiresEmergencyPower()) {
314 console.log('Uruchamianie systemu zasilania awaryjnego!');
315 // activateEmergencyPower(incident.affectedAreas);
316 }
317 }
318
319 else if (incident instanceof VisitorIncident) {
320 if (incident.requiresMedicalTeam()) {
321 console.log(`Wysyłanie zespołu medycznego do lokalizacji: ${incident.location}`);
322 // dispatchMedicalTeam(incident.location, incident.injuryLevel, incident.visitorCount);
323
324 // Aktualizacja statusu medycznego
325 this.updateIncident(incidentId, inc => inc.updateMedicalStatus('dispatched'));
326 }
327
328 if (incident.requiresEvacuation()) {
329 console.log(`Rozpoczynam ewakuację gości z: ${incident.location}`);
330 // evacuateVisitors(incident.location);
331 }
332 }
333
334 // Wspólne reakcje dla wszystkich incydentów
335 if (incident.requiresNotification()) {
336 console.log('Powiadamianie kierownictwa parku...');
337 // notifyParkManagement(incident.getSummary());
338 }
339 }
340}
341
342// Przykład użycia systemu incydentów
343function demoParkIncidentSystem() {
344 const incidentSystem = new IncidentManagementSystem();
345
346 // Dodajemy słuchacza dla nowych incydentów
347 incidentSystem.addEventListener('new', ({ id, incident }) => {
348 console.log(`NOWY INCYDENT [${id}]: ${incident.name} w lokalizacji ${incident.location}`);
349 });
350
351 // Raportowanie incydentu z dinozaurem
352 const raptorIncidentId = incidentSystem.reportIncident(
353 new DinosaurEscapeIncident(
354 'Ucieczka Velociraptorów z zagrody',
355 'Sektor C4',
356 'Velociraptor',
357 3,
358 9 // Wysoki poziom zagrożenia
359 )
360 );
361
362 // Aktualizacja incydentu - zmiana ostatniego spostrzeżenia
363 setTimeout(() => {
364 incidentSystem.updateIncident(raptorIncidentId, incident => {
365 incident.updateSighting('Sektor C5 - w pobliżu centrum odwiedzających');
366 console.log(`Aktualizacja: Raptory zauważono w ${incident.lastSighting}`);
367 });
368 }, 2000);
369
370 // Raportowanie incydentu systemowego
371 const powerIncidentId = incidentSystem.reportIncident(
372 new SystemFailureIncident(
373 'Awaria zasilania ogrodzeń elektrycznych',
374 'Sektor B1-B3',
375 'electric_fences',
376 ['TRex Paddock', 'Raptor Containment'],
377 'offline' // Backup nie działa
378 )
379 );
380
381 // Raportowanie incydentu z gośćmi
382 const visitorIncidentId = incidentSystem.reportIncident(
383 new VisitorIncident(
384 'Goście poza wyznaczoną trasą zwiedzania',
385 'Sektor D2',
386 4, // Liczba gości
387 'minor', // Drobne obrażenia
388 'not_required' // Status medyczny
389 )
390 );
391
392 // Wyświetlanie aktywnych incydentów
393 setTimeout(() => {
394 console.log('\n--- AKTYWNE INCYDENTY ---');
395 console.table(incidentSystem.getActiveIncidents());
396 }, 3000);
397
398 // Rozwiązanie incydentu z gośćmi
399 setTimeout(() => {
400 incidentSystem.resolveIncident(
401 visitorIncidentId,
402 'Goście zostali bezpiecznie eskortowani z powrotem na wyznaczoną trasę zwiedzania.'
403 );
404 console.log(`Incydent ${visitorIncidentId} został oznaczony jako rozwiązany.`);
405 }, 4000);
406
407 // Rozwiązanie incydentu z zasilaniem
408 setTimeout(() => {
409 incidentSystem.resolveIncident(
410 powerIncidentId,
411 'Zasilanie przywrócone, ogrodzenia ponownie aktywne.'
412 );
413 console.log(`Incydent ${powerIncidentId} został oznaczony jako rozwiązany.`);
414 }, 5000);
415
416 // Rozwiązanie incydentu z raptorami
417 setTimeout(() => {
418 incidentSystem.resolveIncident(
419 raptorIncidentId,
420 'Wszystkie 3 Velociraptory złapane i bezpiecznie przetransportowane z powrotem do zagrody.'
421 );
422 console.log(`Incydent ${raptorIncidentId} został oznaczony jako rozwiązany.`);
423
424 // Wyświetlenie podsumowania incydentu
425 const incidentDetails = incidentSystem.getIncidentById(raptorIncidentId);
426 console.log('\n--- SZCZEGÓŁY ROZWIĄZANEGO INCYDENTU ---');
427 console.log(JSON.stringify(incidentDetails, null, 2));
428 }, 6000);
429}
430
431// Uruchomienie demonstracji
432// demoParkIncidentSystem();toJSON(), aby błędy można było łatwo logować i przesyłaćsuper(message) w konstruktorze, aby zachować ślad stosuWłasne klasy błędów to potężne narzędzie w arsenale programisty JavaScript. W złożonych aplikacjach, takich jak system zarządzania Parkiem Jurajskim, precyzyjna kategoryzacja i obsługa różnych typów błędów jest kluczowa dla utrzymania bezpieczeństwa i stabilności.
Pamiętaj, że jak powiedział Dr. Ian Malcolm: "Życie... uh... znajdzie sposób." To samo dotyczy błędów w kodzie. Najlepszym podejściem jest nie udawać, że błędy nie istnieją, ale spodziewać się ich i być przygotowanym na ich obsługę w jak najbardziej elegancki i skuteczny sposób.
W następnym ćwiczeniu wykorzystamy wszystkie poznane techniki do implementacji pełnej aplikacji, która będzie demonstrować moduły, asynchroniczność i obsługę błędów w praktyce.