Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ.

Γεια

Προσπαθώντας να καταλάβω τις callbacks στη javascript δημιουργησα το παρακατω

 

        function foo(f) {
          this.j = 0;
          setInterval(function() {
            this.j = 4;
          }.bind(this), 3000);
          return f(this.j);
        }

        var jb = foo(function(n){
          return n;
        });

        alert (jb);

Το οποίο δουλεύει, αλλά κάνει alert 0, ενω θέλω να κάνει alert 4. Καταλαβαίνω γιατί δεν κάνει alert 4 --δεν προλαβαίνει να πάρει τη τιμή 4, το κάνω return κατευθείαν ουσιαστικά.

Αυτό που δε καταλαβαίνω είναι πως να γυρίσω το 4 μέσα στο j της foo μόλις είναι έτοιμο και μετά να το κάνω return.

 

Εχω προσπαθήσει διαφορες επικές χαζομάρες, όπως

        function foo(f) {
          this.j = 0;
          return f(setInterval(function() {
            return this.j = 4;
          }.bind(this), 3000))    ;    
        }

κανει alert 1 ??? Υποθέτω επιστρεφει κάποιο true του setInterval?

Επίσης,

        function foo(f) {
          this.j = 0;
          function a(f){
            setInterval(function() {
              this.j = 4;
              return f(this.j);
            }.bind(this), 3000)
          };
          f(
            a(
             function(b){
              return b;
             }
            )
          );
        }

κανει alert undefined.

 

Λίγη βοήθεια? Ευχαριστώ

Δημοσ. (επεξεργασμένο)

Αν έβλεπες το documentation για την setInterval, θα ήξερες ότι επιστρέφει ένα id.

https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval

var intervalID = scope.setInterval(code, delay);

Η συνάρτηση που της περνάς τρέχει ΑΡΓΟΤΕΡΑ. Δεν θα σου επιστρέψει τιμή που θα την πάρεις και θα την βάλεις στο alert. Γιατί; Επειδή μέχρι να τρέξει, ο υπόλοιπος κώδικάς σου έχει ήδη εκτελεστεί.

Σκέψου το ως εξής:

Τρέχεις, τρέχεις, τρέχεις, πετάς μια χλαπάτσα στον ουρανό, τρέχεις, τρέχεις, η χλαπάτσα πέφτει κάτω αλλά όχι επάνω σου γιατί έχεις φύγει.

Επεξ/σία από paparovic
Δημοσ.

Σ'ευχαριστω. Οκ, στη θεωρία το έχω καταλάβει, στη πράξη δε ξερω πως να κανω κωδικα το παρακάτω

μολις γινει το this.j 4 στην setInterval

γυρνα το στην foo

απο την foo στην jb

συνεχισε τη ζωη σου

στο documentation λεει για τη function της setInterval οτι " no return value is expected ". Οπότε πρέπει να αλλάξω εντελώς τη συνταξη μου, μιας και η setInterval function δε θα επιστρεψει ποτε τιποτα?

Δημοσ.
function erxomaiApoToMellon() {
  return new Promise(resolve => {
    setTimeout(()=> {    
    	resolve(4);
    }, 1000);
  }) 
}

async function trexw() {
    let x = 1;
    x = await erxomaiApoToMellon();
    console.log(x)	// 4;
}

trexw();

 

Δημοσ.

Η ερώτηση είναι πολύ καλή, απλά δεν συνεχίζεις το σκεπτικό λίγο παραπέρα για να μπεις στο σωστό δρόμο.

Τι πάει να πει "να επιστρέψω όταν γίνει 4"; Οι κανόνες είναι απλοί, επιστρέφεις μόλις δεις return ή φτάσεις στο τέλος της function. "Να επιστρέψω όταν" με την έννοια του return δεν υπάρχει και ποτέ δε θα υπάρξει.

Αυτό με τη σειρά του σημαίνει πως δεν είναι δυνατόν να φτιάξεις οτιδήποτε που μέσα στο evaluation του θα περιέχει κλήση της foo (για την επιστροφή της οποίας μιλάμε) το οποίο θα λάβει υπόψη του το 4.

Αυτό που μπορείς να κάνεις, είναι να στήσεις μια κατάσταση *άσχετη με την επιστρεφόμενη τιμή* η οποία να λέει "όταν γίνει 4, κάνε αυτό". Οπότε ξεχνάς το return ως μέσο σηματοδοσίας και ψάχνεις άλλη τεχνική.

Με σειρά χρονολογικής εμφάνισης, οι τεχνικές που μπορείς να χρησιμοποιήσεις (εκτός της πλέον άθλιας που δεν την αναφέρω καν για λόγους κάρμα) είναι:

1. Continuation passing style (δηλαδή callback)

2. Promise

3. Async/await

Στην πραγματικότητα μιλάμε για το ίδιο ακριβώς πράγμα σαν ιδέα, το μόνο που αλλάζει είναι *ο τρόπος με τον οποίο μπορείς να το εκφράσεις σε κώδικα*. Κράτα το στο μυαλό σου αυτό: ο μηχανισμός είναι πάντα ο ίδιος, το μόνο που αλλάζει είναι πόσο εύκολα και βολικά μπορείς να πεις στον compiler τι θέλεις να γίνει.

Θα σου πρότεινα τώρα να ψαχτείς λίγο για το πώς θα το κάνεις αυτό old skool με callback (hint: όπως το κάνει η setInterval, ή ισοδύναμα η setTimeout -- πώς της λες "όταν περάσει Χ χρόνος θέλω να γίνει αυτό"?), γιατί αν το καταλάβεις αυτό και κρατήσεις στο μυαλό σου ότι και τα άλλα δεν είναι τίποτα παραπάνω από διαφορετική αποτύπωση σε source code που είναι πιο εύκολα κατανοητή από ανθρώπους, τα έχεις καταλάβει όλα.

Ψήσου λίγο κι εδώ είμαστε.

 

Δημοσ. (επεξεργασμένο)

Ελπιζω να βοηθησω καποιον μπερδεμενο σα και μενα, και οπου αλλου κανω λαθος, διορθωστε με

Ας πουμε

οτι ο κωδικας κανει καποια πραγματα, μετα χρειαζεται να κανει ενα callback και μετα συνεχιζει να κανει καποια αλλα πραγματα

Το λάθος

τα πιο πολλά παραδείγματα για callbacks εκει εξω εχουν το εξης αισχος

         console.log('kapoia alla pragmata 1');

        function foo(f) {
          this.j = 0;
          f(this.j);
        }

        foo(function(n){
          console.log(n);
        });        

        console.log('kapoia alla pragmata 2');

το οποιο δε με βοηθαει στο ελαχιστο, μιας και ουσιαστικα ολα καλουντε στη σειρα και ΔΕΝ ΕΙΝΑΙ ΠΡΑΓΜΑΤΙΚΟ ΣΕΝΑΡΙΟ. Περα απο το να δω λιγο τη συνταξη δε με βοηθανε καθολου.

Το σωστο

Η σωστη συνταξη ειναι αυτη

        console.log('kapoia alla pragmata 1');

        function foo(f) {
          this.j = 0;
          setTimeout(function(){
            this.j = 4;
            f(this.j);
          }.bind(this), 3000);
        }

        foo(function(n){
          console.log(n);
        });        

        console.log('kapoia alla pragmata 2');

Ο κωδικας ξεκιναει και κανει καποια πραγματα.

Χρειαζομαι να παρω καποια data απο τη database, το οποιο συνηθως αργει,αναλογα με το query μου.

Καλω τη foo που περνει σαν argument μια callback, την f, η οποια ειναι function. Θα μπορουσε να εχει οτι ονομα θελω, εν συντομια την λεω f. Η foo κανει τα δικα της, καθυστερει και λιγο και μετα γυρναει ενα αποτελεσμα. Εξομοιωνω αυτη τη καθυστερηση με την setTimeout.

Οπως ειπε και ο defacer " επιστρέφεις μόλις δεις return ή φτάσεις στο τέλος της function ", οποτε η setTimeout γυρναει την f(this.j) η οποια ειναι αυτη που στο τελος γυρναει απο την foo με οτι αποτελεσμα εχει. Εδω απλα αλλαζει το j απο 0 σε 4, οποτε γυρναει αυτο το 4 πισω, μεσω ομως της f. Αυτη η f ειναι η function(n) στη κληση της foo. Τσιμπαει λοιπον τη τιμη μεσα απο το n και μετα κανει οτι θελει με αυτο. Στη προκειμενη το κανει απλα console.log.

Γιατι

Επειδη ετσι κανω τον κωδικα μου non-blocking. Το αποτελεσμα στη κονσολα ειναι

kapoia alla pragmata 1
kapoia alla pragmata 2
4

Οσο περιμενω 3 δευτερολεπτα να μου επιστρεψει "4" η foo, ο υπολοιπος κωδικας ειναι ελευθερος να συνεχισει να κανει οτι θελει. Γ αυτο τυπωνει πρωτα το kapoia alla pragmata 1 , μετα ξεκιναει την foo, η foo "παγωνει", αλλα μονο αυτη, και μετα ο κωδικας συνεχιζει και τυπωνει kapoia alla pragmata 2. Μετα απο 3 δευτερολεπτα τυπωνει και το 4 της foo. Ετσι καθυστερησε μονο η foo και οχι ολος ο κωδικας. Αν καθυστερουσε θα ηταν blocking. Τωρα ειναι non-blocking. Η foo ειναι asynchronous. Δηλαδη δε συγχρονιζεται με τον υπολοιπο κωδικα,δεν περιμενει να εκτελεστει με τη σειρα. Επειδη παγωνει, αλλα μονο αυτη, επιτρεπει στον υπολοιπο κωδικα να συνεχισει. Οποτε εχουμε 2 πραγματα ταυτοχρονα. Τον κωδικα να συνεχιζει να τρεχει. Και την foo να κανει τα δικα της, και μολις τελειωσει, επιστρεφει την τιμη της. Αυτο επιτελους με βολευει και ειναι πραγματικο παραδειγμα απο τον πραγματικο κοσμο. Αντι για την foo που τεχνιτα περιμενει, θα μπορουσε να ειναι ενα ajax call, το οποιο ειναι απο τη φυση του asynchronous. Ajax = Asynchronous JavaScript And XML

 

Τι ηθελα

Το αρχικο μου δε δουλευει

function foo(f) {
          this.j = 0;
          setInterval(function() {
            this.j = 4;
          }.bind(this), 3000);
          return f(this.j);
        }

        var jb = foo(function(n){
          return n;
        });

        alert (jb);

γιατι κανω return το this.j πριν τελειωσει η setInterval και του αλλαξει τιμη. Παροτι ειναι μεσα στην f, εκτελειται κατευθειαν και δεν εχει καποια σχεση με την setInterval που καθυστερει 3''. Οποτε γυρναει την αρχικη τιμη του, 0.

Εγω ηθελα να παρω την τιμη της foo και να την βαλω σε μια απλη var. Το οποιο δεν εχει νοημα, μιας και η foo καθυστερει, οποτε, ακομα και τη σωστη συνταξη να παρω και να την διαμορφωσω

        console.log('kapoia alla pragmata 1');

        function foo(f) {
          this.j = 0;
          setTimeout(function(){
            this.j = 4;
            f(this.j);
          }.bind(this), 3000);
        }

        let a = foo(function(n){
          return n;
        });
        console.log(a);

        console.log('kapoia alla pragmata 2');

οοοολος ο κωδικας εκτελειτε, φτανει στο a , το τυπωνει, και ειναι λογικα undefined γιατι η foo ειναι ακομα "παγωμενη", δεν εχει επιστρεψει ακομα το "4". Το επιστρεφει μετα απο 3''. Αλλα μεχρι τοτε ειναι ηδη αργα, ολος ο υπολοιπος κωδικας εκτελεστηκε, το a δεν περιμενει την επιστροφη της foo γιατι ειναι asynchronous. Οποτε αυτο δεν γινετε ετσι. Αν σωνει και καλα πρεπει να αποθηκευτει αυτο σε μια var, πρεπει να ειναι global και να της περασω μια τιμη αμα επιστρεψει

        console.log('kapoia alla pragmata 1');

        var a = 1;
        function foo(f) {
          this.j = 0;
          setTimeout(function(){
            this.j = 4;
            f(this.j);
          }.bind(this), 3000);
        }

        foo(function(n){
          console.log(n);
          a=n;
          console.log('a '+a);
        });
        console.log('a '+a);

        console.log('kapoia alla pragmata 2');

αλλα αυτο παραειναι μπακαλιστικο και δεν εχει καποιο νοημα. Εκτος αν υπαρχει ποιο elegant τροπος, Please πειτε μου.

callback hell, promises, async/await

εν συντομια , οταν μια function εχει μια callback και αυτη μια callback και αυτη μια callback, τοτε γεμιζεις με πολλες nested functions και ο κωδικας γινετε δυσαναγνωστος. Για να το αποφυγουμε αυτο εχουμε τα promises και τα async/await που βασιζονται στα promises, τα οποια ειναι διαφορετικες υλοποιησεις των callbacks, οπως σημειωσε ο defacer και εδωσε το παραδειγμα ο paparovic. Υπηρχαν και τα generators, αλλα δεν νομιζω να χρησιμοποιει κανενας πια. Ευχαιστω btw για τα async/await, δεν τα ηξερα

Για περισσοτερα δειτε

 

 

Επεξ/σία από kordoni

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...