diff --git a/docs-language/asynchronous/3. promises.md b/docs-language/asynchronous/3. promises.md new file mode 100644 index 0000000..ce566e7 --- /dev/null +++ b/docs-language/asynchronous/3. promises.md @@ -0,0 +1,163 @@ +# Promises + +Όταν γράφουμε ασύγχρονο κώδικα στη JavaScript, μία μοντέρνα μεθόδος για να χειριστούμε αποτελέσματα που θα λάβουμε μελλοντικά (όπως απαντήσεις από έναν server), είναι μέσω της χρήσης των Promises. Τα Promises μας επιτρέπουν να οργανώνουμε αλυσιδωτές λειτουργίες και να διαχειριζόμαστε επιτυχίες και αποτυχίες σε ασύγχρονες διαδικασίες, αποφεύγοντας το γνωστό "Callback Hell" που αναφέραμε στην προηγούμενη ενότητα. + +## Δημιουργία ενός Promise + +Ένα Promise δημιουργείται μέσω του constructor `promise`, ο οποίος δέχεται μια συνάρτηση με δύο παραμέτρους. Η συνάρτηση αυτή ονομάζεται executor (εκτελεστής) και εκτελείται αυτόματα μόλις δημιουργηθεί το Promise. + +Τα δύο ορίσματα που δέχεται, `resolve` και `reject`, είναι callback functions και έχουν τις εξής λειτουργίες: + +- resolve: Η διαδικασία επιτυγχάνει και μας επιστρέφεται η τελική τιμή. +- reject: Η διαδικασία αποτυγχάνει και μας επιστρέφεραι ένα error `object`, δηλαδή το exception value. + +```javascript +const myPromise = new Promise((resolve, reject) => { + const success = true; + + if (success) { + resolve("Επιτυχία!"); + } else { + reject("Αποτυχία"); + } +}); +``` +Στο παραπάνω παράδειγμα, η `arrow function` είναι η συνάρτηση executor. Η παράμετρος `resolve` καλείται καθώς η διαδικασία που θέλουμε να εκτελέσουμε στην executor function επιτυγχάνει. + +## Κατάσταση ενός Promise + +Ένα Promise έχει τρείς δυνατές καταστάσεις: + +| Κατάσταση | Περιγραφή | +|-----------|--------------------------------------------| +| `pending` | Το promise δεν έχει ακόμη επιλυθεί | +| `fulfilled` | Το promise επιλύθηκε με επιτυχία | +| `rejected` | Το promise απορρίφθηκε λόγω σφάλματος | + +Μόλις φύγει από την κατάσταση `Pending`, το Promise "κλειδώνει και δεν αλλάζει ξανά κατάσταση. + +## Μέθοδοι then και catch + +Για να χειριστούμε το αποτέλεσμα ενός Promise, χρησιμοποιούμε τις μεθόδους `.then()` και `.catch()`. + +- H `then` καλείται όταν το Promise επιλυθεί επιτυχώς. +- Η `catch` καλείται όταν το Promise απορριφθεί λόγω σφάλματος. + +```javascript +let promise = new Promise((resolve, reject) => { + resolve("success"); +}); + +myPromise + .then((message) => { + console.log("Μήνυμα": message); + }) + .catch((error) => { + console.error("Σφάλμα": error); + }); +``` +- H `then` καλείται όταν το Promise επιλυθεί επιτυχώς. +- Η `catch` καλείται όταν το Promise απορριφθεί λόγω σφάλματος. + +:::tip + +Αν καλέσεις `.then()` ή `.catch()` πάνω σε ένα Promise που έχει *ήδη* επιλυθεί ή απορριφθεί, ο χειριστής θα εκτελεστεί άμεσα, χωρίς καθυστέρηση. Τα Promises είναι *μιας χρήσης* που σημαίνει ότι δεν μπορούν να "επαναληφθούν" ή να "ξαναπροσπαθήσουν". + +::: + + +## Αλυσιδωτές Λειτουργίες (Chaining) + +Ένα από τα χαρακτηριστικά των **Promises** είναι η δυνατότητα να δημιουργόυμε αλυσίδες ενεργειων. Για παράδειγμα: + +```javascript +fetch("https://jsonplaceholder.typicode.com/posts/1") + .then((response) => response.json()) + .then((data) => { + console.log("Δεδομένα:", data) + }); + .catch((error) => { + cosole.error("Σφάλμα στο fetch:", error); + }); +``` +Κάθε `then` επιστρέφει ένα νέο Promise, επιτρέποντας συνεχή επεξεργασία δεδομένων. + +## Παραδείγματα + +* Promise με καθυστέρηση + +```javascript +function delay(ms) { + return new Promise((resolve) => { + setTimeout(() => resolve(`Έγινε μετά από ${ms}ms`), ms); + }); +} + +delay(1000).then((msg) => console.log(msg)); +``` + +* Χειρισμός Σφαλμάτων + +```javascript +function riskyOperation() { + return new Promise((resolve, reject) => { + const ok = Math.random() > 0.5; + ok ? resolve("Όλα καλά") : reject("Κάτι πήγε στραβά"); + }); +} + +riskyOperation() + .then(console.log) + .catch(console.error); +``` + +## Promise.all και Promise.race + +Η Javascript παρέχει μερικές βοηθητικές στατικές μεθόδους για συνδιασμό πολλών **Promises**: + +* `Promise.all` +Εκτελεί πολλά Promises και περιμένει να ολοκληρωθούν όλες. Παράδειγμα: + +```javascript +Promise.all([ + fetch("/data1.json"), + fetch("/data2.json") +]) +.then(([res1, res2]) => Promise.all([res1.json(), res2.json()])) +.then(([data1, data2]) => { + console.log("Δεδομένα 1:", data1); + console.log("Δεδομένα 2:", data2); +}) +.catch(console.error); +``` +Αν ένα αποτύχει, απορρίπτεται ολόκληρο το **Promise**. + +* `Promise.race` +Επιστρέφει το αποτέλεσμα του πρώτου **Promise** που θα ολοκληρωθεί. +```javascript +const fast = new Promise(res => setTimeout(() => res("Γρήγορη"), 500)); +const slow = new Promise(res => setTimeout(() => res("Αργή"), 1000)); + +Promise.race([fast, slow]).then(console.log); // "Γρήγορη" +``` + +# Πλεονεκτήματα Promises + +- Καθαρός κώδικας απο τα callbacks. +- Αποφυγή nested callbacks (callback hell). +- Εύκολος χειρισμός σφαλμάτων με `.catch()`. +- Συμβατότητα με `async/await`, για καθαρότερο κώδικα. + +# Σύγκριση με άλλες μεθόδους + +| Μέθοδος | Πλεονεκτήματα | Μειονεκτήματα | +|---------------|--------------------------------------------|------------------------------------------------| +| Callbacks | Απλή και ευέλικτη | Δύσκολος έλεγχος ροής, callback hell | +| Promises | Καλύτερη ροή, ευκολότερο debugging | Περίπλοκες αλυσίδες μπορεί να μπερδέψουν | +| Async/Await | Συγχρονική μορφή, πιο καθαρός χειρισμός | Απαιτεί κατανόηση των Promises | + + +# Συμπέρασμα + +Τα Promises είναι βασικά εργαλεία για τη συγγραφή ασύγχρονου κώδικα στη Javascript. Διευκολύνουν τον έλεγχο ροής, τον χειρσμό σφαλμάτων και συνεργάζονται άψογα με το `async/await`. Κατανοώντας τα Promises, αποκτάς τον έλεγχο των ασύγχρονων λειτουργιών της Javascript με καθαρό, επεκτάσιμο τροπο. + diff --git a/docs-language/asynchronous/4. async-await.md b/docs-language/asynchronous/4. async-await.md new file mode 100644 index 0000000..ec82803 --- /dev/null +++ b/docs-language/asynchronous/4. async-await.md @@ -0,0 +1,160 @@ +# Async/Await + +Το async/await χρησιμοποιείται για να απλοποιήσει τη διαχείριση ασύγχρονων λειτουργιών που βασίζονται σε Promises. Επιτρέπει τη συγγραφή ασύγχρονου κώδικα με τρόπο που μοιάζει με συγχρονική εκτέλεση, καθιστώντας τον πιο ευανάγνωστο και ευκολότερο στη συντήρηση, ιδιαίτερα σε σύνθετες ροές. + +Η λέξη κλειδί `async` χρησιμοποιείται μπροστά από μία συνάρτηση ή μέθοδο, καθιστώντας την ασύγχρονη. Όταν καλείται, επιστρέφει άμεσα ένα promise, το οποίο εκπληρώνεται μόλις η συνάρτηση επιστρέψει μια τιμή ή απορρίπτεται αν προκύψει εξαίρεση κατά την εκτέλεση. + +Μέσα σε μια τέτοια συνάρτηση, μπορεί να χρησιμοποιηθεί η λέξη κλειδί 'await' για να «παγώσει» προσωρινά την εκτέλεση της μέχρι να ολοκληρωθεί το αντίστοιχο promise. Αν αυτό αποτύχει, ένα exception θα συμβεί στο σημείο του await, επιτρέποντας έτσι τη διαχείριση σφαλμάτων. + +Ας δούμε κάποια παραδείγματα: + +```javascript +async function fetchData() { + const response = await fetch("https://jsonplaceholder.typicode.com/posts/1"); + const data = await response.json(); + console.log(data); +} +fetchData(); + +// { "userId": 1, +// "id": 1, +// "title": "....", +// "body:" "..." } +``` + +Σε αυτό το παράδειγμα, η ασύγχρονη συνάρτηση `fetchData` περιμένει το αποτέλεσμα της εντολής 'fetch' και το μετατρέπει σε JSON πριν το εκτυπώσει. + +```javascript +async function myFunction() { + try { + const result = await someAsyncFunction(); + consolge.log(result); + } + catch (error) { + console.error("Σφάλμα", error.message); + } +} +``` + +Το παραπάνω παράδειγμα δείχνει τη χρήση της ασύγχρονης σύνταξης async/await σε συνδυασμό με τη δομή try/catch για διαχείριση σφαλμάτων. Η myFunction είναι μια ασύγχρονη συνάρτηση που περιμένει το αποτέλεσμα της someAsyncFunction() χρησιμοποιώντας το await. Αν το Promise επιλυθεί επιτυχώς, το αποτέλεσμα αναγράφεται στην κονσόλα. Αν προκύψει σφάλμα κατά την εκτέλεση της ασύγχρονης λειτουργίας, το exception εντοπίζεται στο catch και εμφανίζεται αντίστοιχο μήνυμα σφάλματος. Αυτή η προσέγγιση κάνει τη ροή του κώδικα πιο καθαρή και ευανάγνωστη, σε σύγκριση με τη χρήση 'then()' και 'catch()'. + +## Χειρισμός Σφαλμάτων με try/catch + +Ο χειρισμός σφαλμάτων σε `async` συναρτήσεις γίνεται μεσω της χρήσης της δομής `try/catch`, όπως είδαμε στο προηγούμενο παράδειγμα. Αυτό μας δίνει τον έλεγχο σε κάθε πιθανό σφάλμα που μπορεί να προκύψει κατά την αναμονή ενός Promise. + +```javascript +async function fetchData() { + try { + const response = await fetch('https://api.example.com/data'); + const data = await response.json(); + console.log(data); + } catch (error) { + console.error("Σφάλμα κατά τη λήψη δεδομένων:", error); + } +} +``` + +H `try` "περιμένει" το αποτέλεσμα της `fetch` και η `catch` πιάνει οποιοδήποτε σφάλμα, είτε από το δίκτυο είτε κατά την επεξεργασία των δεδομένων. + +## Συχνές Χρήσεις + +Η σύνταξη async/await χρησιμοποιείται κυρίως σε: + +- Αιτήματα σε APIs +```javascript +sync function fetchUser() { + try { + const response = await fetch('https://jsonplaceholder.typicode.com/users/1'); + const user = await response.json(); + console.log('Χρήστης:', user.name); + } catch (error) { + console.error('Σφάλμα στο fetch:', error.message); + } +} + +fetchUser(); +``` +Χρησιμοποιούμε το λεκτικό `await` για να περιμένουμε την απάντηση ενός API και στη συνέχεια να μετατρέψουμε τα δεδομένα σε JSON. + +- Ανάγνωση αρχείων σε Node.js +```javascript +const fs = require('fs/promise'); + +async function readFileContent() { + try { + const content = await fs.readFile('example.txt', 'utf8'); + console.log('Περιεχόμενο:', content); + } catch(error) { + console.error("Σφάλμα ανάγνωσης αρχείου:", error); + } +} +readFileContent(); +``` +Διαβάζουμε ένα αρχείο τοπικά μέσω `fs.promises.readFile`, χωρίς `.then()` ή εμφώλευση. + +- Διαδοχικές ασύγχρονες λειτουργίες με εξαρτήσεις +```javascript +async function loadUserData() { + try { + const user = await fetchUser(); // Βήμα 1 + const posts = await fetchPosts(user.id); // Βήμα 2 + const comments = await fetchComments(posts[0].id); // Βήμα 3 + + console.log("Σχόλια στην πρώτη ανάρτηση:", comments); + } catch (error) { + console.error("Σφάλμα κατά τη φόρτωση δεδομένων:", error.message) + } +} + +// Dummy async functions +async function fetchUser() { + return { id: 1, name: 'Νίκος' }; +} +async function fetchPosts(userId) { + return [{ id: 101, title: 'Πρώτη Ανάρτηση' }]; +} +async function fetchComments(postId) { + return ['Πολύ καλό άρθρο!', 'Ενδιαφέρον.']; +} + +loadUserData(); +``` +Το παραπάνω παράδειγμα δείχνει πώς μπορούμε να εκτελέσουμε διαδοχικές ασύγχρονες λειτουργίες χρησιμοποιώντας τη σύνταξη async/await. Αρχικά γίνεται ανάκτηση ενός χρήστη, στη συνέχεια φορτώνονται οι αναρτήσεις του και τέλος τα σχόλια της πρώτης ανάρτησης. Όλα αυτά περικλείονται σε δομή try/catch, ώστε να εντοπίζονται και να διαχειρίζονται τυχόν σφάλματα κατά τη διάρκεια της διαδικασίας. Κάθε βήμα εξαρτάται από το προηγούμενο και χωρίς την σύνταξη async/await αυτό θα γινόταν πολύπλοκο με εμφωλευμένα `.then()`. + +- Αποφυγή `.then()` chaining και εμφωλευμένων callbacks +```javascript +async function loadProfile() { + try { + const user = await getUser(); + const settings = await getSettings(user.id); + console.log('Ρυθμίσεις για:', user.name, settings); + } catch (error) { + console.error('Σφάλμα:', error.message); + } +} + +// Mock async functions +const getUser = async () => ({ id: 42, name: 'Μαρία' }); +const getSettings = async (userId) => ({ theme: 'dark', language: 'el' }); + +loadProfile(); +``` +Αντί για `getUser().then().then()...,` χρησιμοποιούμε await για να γράψουμε τον κώδικα σε "γραμμική" μορφή. + +## Πλεονεκτήματα της async/await +- Βελτιωμένη Αναγνωσιμότητα: Ο κώδικας είναι πιο ευανάγνωστος και μοιάζει συγχρονικός. +- Εύκολος Χειρισμός Σφαλμάτων: Η χρήση `try/catch` κάνει τον χειρισμό σφαλμάτων πολύ πιο απλό. +- Αποφυγή Callback Hell: Δεν χρειάζονται εμφωλευμένα callbacks ούτε μακροσκελείς αλυσίδες `.then()`. +- Καλύτερο Debugging: Ο εντοπισμός σφαλμάτων είναι πιο απλός, καθώς η ροή θυμίζει συγχρονικό κώδικα. + +## 5. Σύγκριση με άλλες προσεγγίσεις + +| Προσέγγιση | Πλεονεκτήματα | Μειονεκτήματα | +|----------------|--------------------------------------------------------|----------------------------------------------------------| +| **Callbacks** | Απλή υλοποίηση, παλιότερη υποστήριξη | Callback hell, δύσκολος έλεγχος σφαλμάτων | +| **Promises** | Αλυσιδωτές λειτουργίες, καλύτερη από τα callbacks | Ακόμη δύσκολος χειρισμός σε πολύπλοκες ροές | +| **Async/Await**| Καθαρός και ευθύγραμμος κώδικας, χρήση try/catch | Απαιτεί κατανόηση των Promises και ES2017+ περιβάλλον | + + + +