Che cosa sono i callback posticipati?

14

Capisco l'idea di un callback, in cui passo una funzione in un'altra funzione e tale funzione utilizza quindi a piacimento la funzione fornita.

Sto facendo fatica a capire i callback posticipati, anche dopo averlo fatto su Google.

Qualcuno potrebbe fornire una spiegazione semplice per favore? Programmo in Ruby, ma conosco anche C / C ++, ma soprattutto sono stato un programmatore esperto in linguaggio assembly. Quindi mi chiedo è un po 'come una pila di indirizzi di richiamata che vengono pop-d? Spero di imparare jquery o node.js e questi callback differiti sembrano parte integrante di entrambi. Comprendo i principi di base del threading (sebbene l'oggetto mutex mi faccia male alla testa;)

    
posta tentimes 09.04.2012 - 15:36
fonte

5 risposte

3

Su richiesta, ecco i commenti presentati come risposta:

Non sono sicuro che tu abbia completamente a che fare con il fatto che le funzioni in JS sono oggetti di prima classe, e possono quindi essere archiviate fino al momento necessario, oltre il tempo di creazione.

Ad esempio, supponiamo di voler scrivere su un file, quindi stampare un messaggio di log; quindi chiami la funzione "write ()" (o qualsiasi altra cosa) e passa una funzione che emette il messaggio di log (questa è la funzione di callback posticipata). "write ()" memorizza internamente un riferimento alla funzione data, inizia a scrivere sul file e imposta il proprio callback per sapere quando la scrittura è terminata. Quindi torna prima che la scrittura sia completata; quando lo è, il callback interno viene in qualche modo chiamato (questo è il lavoro del framework sottostante - nel caso di node.js, è fatto con un loop di eventi), che quindi chiama il callback che stampa il messaggio di log.

La parte "differita" indica semplicemente che la funzione di richiamata non viene chiamata immediatamente; chiamandolo posticipato fino al momento appropriato. Nel caso di funzioni asincrone come molte di quelle in node.js, il callback specificato viene generalmente chiamato quando l'operazione viene completata (o si verifica un errore).

La maggior parte delle cose è asincrona in node.js, ma nel browser con ad es. jQuery, la maggior parte delle cose è effettivamente sincrona (tranne, ovviamente, per le richieste AJAX). Poiché le funzioni di prima classe sono così utili in JavaScript (soprattutto a causa del grande supporto di chiusura), i callback vengono utilizzati ovunque nel browser, ma non vengono "posticipati" per le operazioni sincrone (a meno che non vengano chiamati immediatamente da tu, ma in seguito dalla funzione che chiami).

Il fatto che il sistema sottostante sia basato sugli eventi è ortogonale all'uso di callback posticipati; puoi immaginare una versione (molto lenta) di node.js che ha avviato un thread per ogni operazione, quindi chiama il tuo callback dato quando il thread ha terminato il suo lavoro, senza utilizzare affatto gli eventi. Certo, questo è un modello orribile, ma illustra il mio punto: -)

    
risposta data 09.04.2012 - 20:09
fonte
7

Il modo in cui funziona una callback posticipata ogni volta che si aggiunge una richiamata ad esso, tale callback viene trasferito a un array. Quindi, quando il metodo .resolve() o .resolveWith() viene chiamato sull'oggetto posticipato, tutte le callback .done() nell'array vengono eseguite nell'ordine.

Ora possiamo vedere cos'è un oggetto differito. Prendi lo snippet qui sotto come esempio.

var deferred = $.Deferred();
var promise = deferred.promise();

Quello che abbiamo ora è un oggetto posticipato e l'oggetto promessa dell'oggetto posticipato. L'oggetto differito ha tutti gli stessi metodi dell'oggetto promessa, tuttavia l'oggetto promessa ha solo i metodi .done() , .fail() e .always() che vengono utilizzati per aggiungere callback all'oggetto posticipato per ogni rispettivo event . L'oggetto differito invece ha molti altri metodi, soprattutto .resolve() e .reject() . Quando questi metodi vengono richiamati sull'oggetto posticipato, vengono richiamati tutti i callback. .resolve() attiva i callback .done() e .always() mentre il metodo .reject() chiama .fail() e .always() callback.

Generalmente l'oggetto posticipato viene tenuto nascosto all'interno di un ambito privato e l'oggetto promessa viene restituito dalla funzione in modo che i callback possano essere inseriti su di esso. L'oggetto posticipato verrà risolto in seguito, ad esempio dopo che una richiesta Ajax è stata completata o dopo che un'immagine è stata caricata, dopo un setTimeout, ecc. È anche importante rendersi conto che un oggetto posticipato può essere risolto solo una volta. Se è già stato risolto, verranno richiamati immediatamente i callback.

Ecco un altro esempio, uno che uso:

function loadImage(url) {
    var def = $.Deferred(),
        img = new Image();
    $(img).on("load error",function(e){
        if (e.type === "error") {
            def.reject(url);
        }
        else {
            def.resolve(url);
        }
    });
    img.src = url;
    // return the promise object so that callbacks can
    // be defined on the deferred object.
    return def.promise();
}
loadImage("foobar.jpg").done(function(){
    alert("The image is loaded!");
}).fail(function(){
    alert("The image failed to load!");
}).always(function(){
    alert("This is always called!");
});

Per ulteriori informazioni sul metodo $.Deferred() di jQuery e sugli oggetti posticipati, visita link

    
risposta data 09.04.2012 - 16:24
fonte
3

Non sono sicuro, ma credo che una richiamata differita si riferisca ad una callback asincrona, quindi avrai una fortuna migliore su googleing.

La migliore spiegazione che ho trovato è stata al link

Hey, probablyExpensiveFunction(), please do your stuff, but I, the single Node.js thread, am not going to wait right here until you are finished, I will continue to execute the lines of code below you, so would you please take this callbackFunction() here and call it when you are finished doing your expensive stuff? Thanks!"

In questo esempio, probablyExpensiveFunction è una funzione non bloccante (o asincrona). Ciò significa che non viene eseguito immediatamente, ma inserito in un cosiddetto loop di eventi. Il thread node.js continuerà l'esecuzione, ma ad un certo punto nel tempo, deciderà di eseguire qualcosa dal ciclo degli eventi. Quando raggiunge probabilmenteExpensiveFunction, lo chiama e, quando probabilmenteExpensiveFunction termina l'esecuzione, chiama il callback (differito) passato come parametro ad esso.

Come esempio di ProbabilitàExpensiva puoi prendere fs.readFile

    
risposta data 09.04.2012 - 15:49
fonte
3

JavaScript è a thread singolo, quindi non puoi pensare in termini di thread per capirlo. Ecco un esempio di callback regolari e asincroni che utilizzano jQuery:

var regularCallback = function(evt) {
    alert("I'm a callback!")
}
var asyncCallback = function(data) {
    alert("I only run when an async operation finishes!")
}

// Bind the regular callback to a button's click event
$('#mybutton').on('click', regularCallback);

// Start an ajax request to the server. The request is asynchronous, so code
// below this line will execute immediately. The callback function
// will only be called when the request is complete.
$.get("http://google.com", asyncCallback);
    
risposta data 09.04.2012 - 16:09
fonte
1

Le callback differite (alias Promotions ) consentono di scrivere codice sequenziale asincrono, senza dolore e callback spaghetti:

$.when( doAjax(), doAnotherAjax() ).then( haveFunWithMoreAjax ).then( animateStuff );

'when' consente di attendere il ritorno delle funzioni in parallelo e then può essere concatenato in sequenza.

una nota: jQuery differite ! = Promises / A , la loro sintassi è leggermente diversa.

Ci sono buoni articoli sull'argomento: uno a IEBlog e altri in alcuni blog casuali , a libro e un popolare domanda stackoverflow

    
risposta data 09.04.2012 - 17:05
fonte

Leggi altre domande sui tag