Προγραμματισμός

Ασύγχρονη JavaScript: Επεξήγηση επιστροφών και υποσχέσεων

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

Οι επιστροφές κλήσεων ήταν ο μόνος εγγενώς υποστηριζόμενος τρόπος αντιμετώπισης του κώδικα ασύγχρονου έως το 2016, όταν το Υπόσχεση αντικείμενο εισήχθη στη γλώσσα. Ωστόσο, οι προγραμματιστές JavaScript εφάρμοζαν παρόμοια λειτουργικότητα τα δικά τους χρόνια προτού φτάσουν οι υποσχέσεις στη σκηνή. Ας ρίξουμε μια ματιά σε μερικές από τις διαφορές μεταξύ επιστροφών κλήσεων και υποσχέσεων και ας δούμε πώς αντιμετωπίζουμε τον συντονισμό πολλαπλών υποσχέσεων.

Οι ασύγχρονες συναρτήσεις που χρησιμοποιούν επιστροφές κλήσης λαμβάνουν μια συνάρτηση ως παράμετρο, η οποία θα καλείται μόλις ολοκληρωθεί η εργασία. Αν έχετε χρησιμοποιήσει κάτι σαν setTimeout στο πρόγραμμα περιήγησης, έχετε χρησιμοποιήσει επιστροφές κλήσεων.

// Μπορείτε να ορίσετε την επιστροφή κλήσης ξεχωριστά ...

αφήστε το myCallback = () => {

console.log ('Called!');

};

setTimeout (myCallback, 3000);

//… αλλά είναι επίσης συνηθισμένο να βλέπουμε τις επιστροφές κλήσεων να ορίζονται εν σειρά

setTimeout (() => {

console.log ('Called!');

}, 3000);

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

// Θα χρησιμοποιούσαμε τη νέα μας λειτουργία ως εξής:

waitCallback (3000, () => {

console.log ('Called!');

});

Ένθετες επιστροφές και η πυραμίδα της καταστροφής

Τα callbacks λειτουργούν καλά για το χειρισμό ασύγχρονου κώδικα, αλλά γίνονται δύσκολα όταν αρχίσετε να συντονίζετε πολλές ασύγχρονες λειτουργίες. Για παράδειγμα, εάν θέλαμε να περιμένουμε δύο δευτερόλεπτα και να καταγράψουμε κάτι, περιμένετε τρία δευτερόλεπτα και να καταγράψετε κάτι άλλο, στη συνέχεια περιμένετε τέσσερα δευτερόλεπτα και καταγράψτε κάτι άλλο, η σύνταξή μας γίνεται βαθιά ένθετη.

// Θα χρησιμοποιούσαμε τη νέα μας λειτουργία ως εξής:

waitCallback (2000, () => {

console.log ('First Callback!');

waitCallback (3000, () => {

console.log ('Second Callback!');

waitCallback (4000, () => {

console.log ('Third Callback!');

    });

  });

});

Αυτό μπορεί να φαίνεται σαν ένα ασήμαντο παράδειγμα (και είναι), αλλά δεν είναι ασυνήθιστο να υποβάλλετε πολλά αιτήματα ιστού στη σειρά με βάση τα αποτελέσματα επιστροφής ενός προηγούμενου αιτήματος. Εάν η βιβλιοθήκη σας AJAX χρησιμοποιεί επιστροφές κλήσεων, θα δείτε ότι η παραπάνω δομή παίζεται. Σε παραδείγματα που είναι βαθύτερα ένθετα, θα δείτε τι αναφέρεται ως η πυραμίδα της μοίρας, η οποία παίρνει το όνομά της από το σχήμα της πυραμίδας που δημιουργείται στο κενό διάστημα στην αρχή των γραμμών.

Όπως μπορείτε να δείτε, ο κώδικάς μας διαρθρώνεται και δυσκολεύεται να διαβαστεί όταν ασχολείται με ασύγχρονες λειτουργίες που πρέπει να συμβούν διαδοχικά. Αλλά γίνεται ακόμη πιο δύσκολο. Φανταστείτε εάν θέλαμε να ξεκινήσουμε τρία ή τέσσερα αιτήματα ιστού και να εκτελέσουμε κάποια εργασία μόνο μετά την επιστροφή όλων. Σας ενθαρρύνω να το κάνετε αν δεν έχετε αντιμετωπίσει την πρόκληση στο παρελθόν.

Ευκολότερος συγχρονισμός με υποσχέσεις

Οι υποσχέσεις παρέχουν ένα πιο ευέλικτο API για την αντιμετώπιση ασύγχρονων εργασιών. Απαιτεί η συνάρτηση να γράφεται έτσι ώστε να επιστρέφει a Υπόσχεση αντικείμενο, το οποίο έχει ορισμένα τυπικά χαρακτηριστικά για τον χειρισμό μεταγενέστερης συμπεριφοράς και τον συντονισμό πολλαπλών υποσχέσεων. Αν μας waitCallback η λειτουργία ήταν Υπόσχεση-με βάση, θα χρειαζόταν μόνο ένα επιχείρημα, το οποίο είναι τα χιλιοστά του δευτερολέπτου να περιμένουμε. Οποιαδήποτε επόμενη λειτουργικότητα θα ήταν αλυσοδεμένος από την υπόσχεση. Το πρώτο μας παράδειγμα θα μοιάζει με αυτό:

αφήστε το myHandler = () => {

console.log ("Κλήθηκε!");

};

waitPromise (3000). τότε (myHandler);

Στο παραπάνω παράδειγμα, waitPromise (3000) επιστρέφει a Υπόσχεση αντικείμενο που έχει ορισμένες μεθόδους για να χρησιμοποιήσουμε, όπως έπειτα. Εάν θέλαμε να εκτελέσουμε πολλές ασύγχρονες λειτουργίες το ένα μετά το άλλο, θα μπορούσαμε να αποφύγουμε την πυραμίδα της μοίρας χρησιμοποιώντας υποσχέσεις. Αυτός ο κωδικός, που ξαναγράφηκε για να υποστηρίξει τη νέα μας υπόσχεση, θα μοιάζει με αυτόν:

// Ανεξάρτητα από το πόσα διαδοχικά καθήκοντα ασύγχυσης έχουμε, δεν κάνουμε ποτέ την πυραμίδα.

waitPromise (2000)

.then (() => {

console.log ('First Callback!');

επιστροφή waitPromise (3000);

  })

.then (() => {

console.log ('Second Callback!');

επιστροφή waitPromise (4000);

  })

.then (() => {

console.log ('Second Callback!');

επιστροφή waitPromise (4000);

  });

Ακόμα καλύτερα, αν χρειαστεί να συντονίσουμε ασύγχρονες εργασίες που υποστηρίζουν τις Υποσχέσεις, θα μπορούσαμε να χρησιμοποιήσουμε όλα, η οποία είναι μια στατική μέθοδος στο Υπόσχεση αντικείμενο που παίρνει πολλές υποσχέσεις και τις συνδυάζει σε μία. Θα μοιάζει με:

Promise.all ([

waitPromise (2000),

waitPromise (3000),

waitPromise (4000)

τότε) (() => console.log ('Όλα γίνονται!'));

Την επόμενη εβδομάδα, θα ανακαλύψουμε περαιτέρω πώς λειτουργούν οι υποσχέσεις και πώς να τις χρησιμοποιούμε ιδιώματα. Εάν απλώς μαθαίνετε JavaScript ή σας ενδιαφέρει να δοκιμάσετε τις γνώσεις σας, δοκιμάστε να waitCallback ή προσπαθήστε να επιτύχετε το αντίστοιχο του Υπόσχεση. Όλα με επιστροφές.

Όπως πάντα, επικοινωνήστε μαζί μου στο Twitter με τυχόν σχόλια ή ερωτήσεις.