kordoni Δημοσ. 1 Ιανουαρίου 2016 Δημοσ. 1 Ιανουαρίου 2016 Κολλαω με callbacks και scope. Λοιπον, εχω αυτο εδω Item.prototype.save = function (fn){ var item = this; var itemcode ; fixCode(item.code, function(c) { itemcode=c; }); var query=client.query('INSERT INTO item(//....insert itemcode } function fixCode(code, fn){ var code = code; prepareCode(code,function(error, finalCode) { fn(finalCode); }); } Επειδη η fixCode ειναι ασυγχρονη, ενα απλο return δεν αρκει, περναμε μια callback και στελνει το finalCode μεσα στην Item.prototype.save, μεσα στο fixCode που την καλεσε, οποτε τωρα το c ειναι ισο με τη νεα επεξεργασμενη τιμη απο το fixCode. Μεχρι εδω καλα. Δεν μπορω να περασω το c στο itemcode. Το itemcode ειναι ορισμενο μεσα στην Item.prototype.save , γιατι δεν μπορει να παρει τη τιμη c? Scope υποθετω ετσι? Εκτος του fixCode(item.code, function( c ) { το itemcode ειναι παλι αδειο. Μεσα στο query, το itemcode ειναι αδειο. Εξηγηστε μου σας παρακαλω γιατι δεν δουλευει και πως μπορω να περασω το c στο itemcode. Θα πρεπει να υπαρχει καποιος απλος τροπος. Θελω τον πιο απλο τροπο για να δω πως δουλευει η javascript και να μαθαινω την απλη λογικη της, χωρις hacks. Θενξ
defacer Δημοσ. 2 Ιανουαρίου 2016 Δημοσ. 2 Ιανουαρίου 2016 Απλά σκάλωσες λίγο χωρίς ιδιαίτερο λόγο. Το λες και μόνος σου ότι η fixCode είναι async, επομένως για να κάνεις κάτι με την τιμή που θα σου παρέχει πρέπει να περάσεις ένα callback, καθώς μόνο όταν εκτελεστεί αυτό θα είναι διαθέσιμη η τιμή. Λοιπόν τι είναι αυτό που θέλεις να κάνεις με την τιμή και άρα πρέπει να βρίσκεται αναγκαστικά μέσα στο σώμα του callback, δεδομένου ότι σε οποιαδήποτε άλλη περίπτωση δε θα έχει πρόσβαση στην τιμή; ΥΓ εφόσον ενδιαφέρεσαι να μάθεις σωστά, μη σπαταλήσεις πολύ χρόνο παλεύοντας με callbacks σαν μηχανισμό ελέγχου ροής του προγράμματος όταν εμπλέκονται async συναρτήσεις. Μείνει μέχρι να το νιώσεις, απο κει και πέρα όταν πας να κάνεις κάτι σοβαρό θα δεις ότι πολύ σύντομα θα βρεθείς στο λεγόμενο callback hell. Όταν φτάσεις εκεί σταμάτα να παιδεύεσαι και ψάξε για κάποια εναλλακτική. Για κάτι που είναι στάνταρ στην ES6, θα το συναντάς συχνά μπροστά σου και λύνει όχι μόνο αυτό αλλά και άλλα προβλήματα: promises. Αυτή τη στιγμή που μιλάμε μία από τις καλύτερες (η καλύτερη?) υλοποίηση θεωρείται η bluebird.
kordoni Δημοσ. 2 Ιανουαρίου 2016 Μέλος Δημοσ. 2 Ιανουαρίου 2016 Ναι, η λογικη μου ηταν >στειλε το item.code απο την Item.prototype.save στο fixCode να αλλαξει >οταν γυρισει συνεχιζεις την εκτελεση της Item.prototype.save με το νεο πλεον itemcode δε μπορω να ξεφορτωθω τη synchronous λογικη τοσο ευκολα τελικα Αλλα βλεπω οτι δε μπορω να περασω το itemcode πισω στην Item.prototype.save. Πριν τα promises θα δοκιμασω να κανω το fixCode μεθοδο του Item and let u guys know
kordoni Δημοσ. 2 Ιανουαρίου 2016 Μέλος Δημοσ. 2 Ιανουαρίου 2016 Ωραια, ας κανουμε το fixCode μεθοδο του Item. Item.prototype.save = function (fn){ var item = this; Item.fixCode(item.code, function(c) { Item.code=c; }); var query=client.query('INSERT INTO item(//....Use Item.code } Item.fixCode = function(code, fn){ var code = code; prepareCode(code,function(error, finalCode) { fn(Item.code = finalCode); }); } Και παλι το Item.code εχει τιμη μονο μεσα στο Item.fixCode(item.code, function©. Εξω απο αυτο, στο query πχ, δεν εχει. Εδω μιλαμε οτι αλλαζω με object method μια τιμη του object. Δεν θα επρεπε η τιμη του object να εχει αλλαξει παντου? Αφου μιλαμε οτι πειραζω το object? Το οποιο δεν επηρεαζεται απο scope των ιδιων των μεθοδων του? Δηλαδη ελεος? Αλλαζω τη τιμη Item.code μια μεσα στον ορισμο της Item.fixCode και μια οταν τη καλω στο Item.prototype.save και προφανως ακομα δεν καταφερνω αυτο που θελω. Παρακαλω, τι κανω λαθος παλι? θενξ
defacer Δημοσ. 2 Ιανουαρίου 2016 Δημοσ. 2 Ιανουαρίου 2016 Εδω μιλαμε οτι αλλαζω με object method μια τιμη του object. Δεν θα επρεπε η τιμη του object να εχει αλλαξει παντου? Αφου μιλαμε οτι πειραζω το object? Το οποιο δεν επηρεαζεται απο scope των ιδιων των μεθοδων του? Δηλαδη ελεος? Θα έπρεπε, και όντως έχει αλλάξει παντού η τιμή. Το λάθος που κάνεις είναι ότι δεν έχεις καταλάβει με ποιά σειρά εκτελούνται τα διάφορα τμήματα του κώδικα, όχι το ότι δεν μπορείς να περάσεις την τιμή. Η fixCode και οποιαδήποτε άλλη function δεν έχει καμία σημασία αν είναι πάνω στο object ή όχι (αρκεί να έχουν scope οι μεταβλητές που θες). item.prototype.save = function (fn){ var item = this; var itemcode ; fixCode(item.code, function(c) { console.log("Itemcode received = " + c); itemcode=c; }); console.log("Running query...); var query=client.query('INSERT INTO item(...)') // insert itemcode console.log("Query executed with itemcode = " + itemcode); } function fixCode(code, fn){ var code = code; // αυτό εδώ τι το θες; Δεν κάνει απολύτως τίποτα... console.log("Calling prepareCode..."); prepareCode(code,function(error, finalCode) { console.log("Ready to invoke callback with finalCode = " + finalCode); fn(finalCode); }); } Δοκίμασε να τρέξεις αυτό, είναι η πρώτη σου version με μερικά console.log για να καταλάβεις τι συμβαίνει.
kordoni Δημοσ. 3 Ιανουαρίου 2016 Μέλος Δημοσ. 3 Ιανουαρίου 2016 Σε ευχαριστω πολυ γιατι καταλαβα το concept. Οπως ειναι η δομη του πρωτου κωδικα μου, επειδη προκειται για ασυγχρονες functions, παιζει το εξης >καλειται η fixCode και μετα η prepareCode >ασυγχρονο, ο κωδικας του Item.prototype.save συνεχιζει να εκτελειται μεχρι να τελειωσει η prepareCode >αρα εκτελειται insert query >με αδειο itemcode , γιατι το itemcode=c δεν εχει εκτελεστει ακομα (η prepareCode δεν εχει επιστρεψει) >τωρα επεστρεψε η prepareCode και το c, αρα και το itemcode εχει τιμη μια λυση με τον παραπανω κωδικα ειναι να μπει το query μεσα στη κληση της fixCode, like so item.prototype.save = function (fn){ var item = this; var itemcode ; fixCode(item.code, function(c) { console.log("Itemcode received = " + c); itemcode=c; var query=client.query('INSERT INTO item(...)') // insert itemcode }); } οποτε οταν γυρισει η fixCode και το c παρει τιμη, θα συνεχιστει κανονικα και η εκτελεση του query με itemcode που πλεον εχει τιμη. Το ιδιο ακριβως παιζει και στη δευτερη version οπου κανω το fixCode μεθοδο του Item. Φταιει οτι η κληση της Item.fixCode και του query ειναι ακριβως το ενα κατω απο το αλλο και η Item.fixCode ειναι ασυγχρονη. Εκει παω να "κλεψω" και να πλασαρω τη τιμη του finalCode στο Item.code, και καλα το Item object ειναι global και θα ενημερωθει αυτοματα. Ουτε καν. Πρωτα εκτελειται το query με την παλια τιμη του Item.code (αδειο) και μετα επιστρεφει η Item.fixCode που δινει τιμη c στο Item.code. Αν ολος ο κωδικας του query ηταν μεσα στη κληση της Item.fixCode οπως παρακατω, παλι δεν θα επαιζε προβλημα Item.fixCode(item.code, function(c) { Item.code=c; var query=client.query('INSERT INTO item(//....Use Item.code }); } Δεν θεωρω και πολυ καλη πρακτικη να ειναι η μια function μεσα στην αλλη (η prepareCode μεσα στην fixeCode και η το query μεσα στη κληση της fixCode.) Aλλα δε νομιζω οτι υπαρχει αλλη λυση εδω ** σταματαμε σε ενα συγκεκριμενο επιπεδο nesting καθε nesting γινετε μεσα σε συγκεκριμενες functions (Item.save και fixCode) αποφευγουμε callback hell επειδη η fixCode μπορει να ξαναχρειαστει, δε τη βαζουμε μεσα στην οποια Item.save, οποτε δε χρειαζεται να τη ξαναγραφουμε, οποτε κραταμε το Dont Repeat Yourself (DRY - ο κωδικας ειναι στεγνος και καθαρος, για ολη νυχτα και το δερματακι του μενει απαλο) **Παρολα αυτα οποιος εχει λυση που να μη πειραζει τη δομη του αρχικου μου κωδικα και να μην απαιτει nesting, καιγομαι να την ακουσω Θενξ
defacer Δημοσ. 3 Ιανουαρίου 2016 Δημοσ. 3 Ιανουαρίου 2016 Δεν θεωρω και πολυ καλη πρακτικη να ειναι η μια function μεσα στην αλλη (η prepareCode μεσα στην fixeCode και η το query μεσα στη κληση της fixCode.) Aλλα δε νομιζω οτι υπαρχει αλλη λυση εδω ** σταματαμε σε ενα συγκεκριμενο επιπεδο nesting καθε nesting γινετε μεσα σε συγκεκριμενες functions (Item.save και fixCode) αποφευγουμε callback hell επειδη η fixCode μπορει να ξαναχρειαστει, δε τη βαζουμε μεσα στην οποια Item.save, οποτε δε χρειαζεται να τη ξαναγραφουμε, οποτε κραταμε το Dont Repeat Yourself (DRY - ο κωδικας ειναι στεγνος και καθαρος, για ολη νυχτα και το δερματακι του μενει απαλο) **Παρολα αυτα οποιος εχει λυση που να μη πειραζει τη δομη του αρχικου μου κωδικα και να μην απαιτει nesting, καιγομαι να την ακουσω Θενξ Ακριβώς όπως το περιέγραψες γίνεται. Τώρα, γι' αυτό που λες. Είπα παραπάνω για promises και bluebird: Item.prototype.save = function (fn){ var item = this; Promise.promisify(fixCode)(item.code) .then(function(c) { var query=client.query('INSERT INTO item(...)'); // use c }); } και θα μπορούσες να κανονίσεις έτσι τα πράγματα ούτως ώστε όσα callback nesting επίπεδα χρειαζόσουν "κανονικά", εδώ να συνεχίσεις με .then σε ένα μόνο επίπεδο όσο τραβάει η ψυχή σου. Ή ακόμα πιο ιδιωματικά, πολλές φορές δε χρειάζεται ή δεν επιθυμείς να γράψεις inline functions οπότε απλά δίνεις ένα reference: Item.prototype.save = function (fn){ fixCode(this.code).then(insertItem); } όπου έχω κάνει μια σειρά από υποθέσεις για να δουλέψει: h fixCode επιστρέφει promise και η insertItem είναι ήδη bound στο this (ή απλά κάνεις .then(insertItem.bind(this)) όταν την καλείς). Πιστεύω καταλαβαίνεις άμεσα τι δυνατότητες υπάρχουν εδώ για να αλλάξεις τη δομή του κώδικα προς το καλύτερο, και υπόψη: τα promises είναι κανονικές τιμές οπότε μπορείς όχι μόνο να κάνεις construct ένα chain εύκολα αλλά και να περάσεις μισό chain κάπου όπου προστίθεται μετά κι άλλο μισό, κλπ. Γενικά οπωσδήποτε διάβασε για promises (υπάρχει specification που ονομάζεται Promises/A+), ακόμα κι αν δεν είναι η καταλληλότερη λύση εδώ ή δεν τις χρησιμοποιήσεις για οποιοδήποτε λόγο, IMO είναι must know. Θα δεις πως όταν καταλάβεις promises όχι απλά θα κάνεις δουλειές ευκολότερα αλλά θα αλλάξει και ο τρόπος με τον οποίο σκέφτεσαι για τη δομή του κώδικα. Τέλος, κάπου λες για το να είναι μια function μέσα στην άλλη: nothing wrong with that, ίσα ίσα που α) μειώνει το scope της εσωτερικής function (συνήθως αυτό είναι καλό) και β) σου επιτρέπει να δώσεις ένα σύντομο όνομα σ' ένα local κομμάτι κώδικα, ούτως ώστε όταν αυτό χρησιμοποιηθεί παρακάτω να μπορείς να γράψεις κώδικα στο επίπεδο abstraction που θες όσον αφορά τον αναγνώστη. Σύγκρινε: function foo() { getSomePromise().then(function() { var monkey = getMonkey(); if (monkey.isNaughty && whatever_else) { monkey.spank(); } }); } Εδώ ο αναγνώστης αναγκάζεται να φάει ένα mental handbrake εκεί που διαβάζει τη foo() γιατί ξαφνικά είναι υποχρεωμένος να καταλάβει τι ακριβώς γίνεται μέσα στο callback προκειμένου να σχηματίσει μια λογική εικόνα του τι κάνει η foo. Εδώ όμως: function foo() { getSomePromise().then(spankTheMonkey); return; // aka δε χρειάζεται να διαβάσεις παρακάτω εκτός αν θες λεπτομέρειες function spankTheMonkey var monkey = getMonkey(); if (monkey.isNaughty && whatever_else) { monkey.spank(); } } } Αν η επιλογή του ονόματος spankTheMonkey είναι καλή, εδώ ο αναγνώστης καταλαβαίνει τι κάνει η foo μέσα σε 1 sec.
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα