Cosa sono i callback differiti?


15

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

Faccio fatica a capire i callback differiti, anche dopo averlo cercato su Google.

Qualcuno potrebbe fornire una spiegazione semplice per favore? Programma in Ruby, ma conosco anche un po 'C / C ++, ma soprattutto ero un programmatore esperto di linguaggio assembly. Quindi mi chiedo è un po 'come una pila di indirizzi di callback che viene pop? Spero di imparare jquery o node.js e questi callback differiti sembrano integrali per entrambi. Comprendo i principi di threading di base (anche se l'oggetto mutex mi fa male alla testa;)


Intendi gli Deferredoggetti di jQuery ? Si tratta di qualcosa di specifico per Node.js?
bfavaretto,

1
No, intendo in generale. Anche se voglio imparare jquery e possibilmente node.js, ho sentito che avevo bisogno di capire cosa fosse in realtà una callback differita per prima. Ho letto l'articolo di Wikipedia sui callback, ma non sono riuscito a capire i callback differiti, che sembrano intrinseci al paradigma dell'operazione asincrona che sarà coinvolto in questi linguaggi che lo utilizzano.


1
Sto davvero chiedendo l'idea concettuale di callback differito rispetto alla loro implementazione - mi dispiace se non l'ho chiarito. Ho dato altri esempi di linguaggio per spiegare l'idea che sto cercando di chiarire e anche il mio background di programmazione in modo che le persone sapessero come presentare la risposta. Grazie mille per le risposte finora - ci sto arrivando!
tentimes

Ok, penso di aver capito adesso gente, grazie a tutti voi! Non so in che modo rispondere. Cameron ha spiegato il concetto più semplicemente ed era quello che stavo davvero cercando, ma anche altri sono intervenuti e hanno aggiunto le mie conoscenze. Io non sono sicuro che cosa modo per accettare la risposta come io sono nuovo a questo;)
tentimes

Risposte:


4

Su richiesta, ecco i commenti presentati come una risposta:


Non sono sicuro che tu senta completamente il fatto che le funzioni in JS sono oggetti di prima classe e possono quindi essere archiviate fino al momento in cui sono state create.

Ad esempio, supponiamo di voler scrivere su un file, quindi stampare un messaggio di registro; quindi chiamate la funzione "write ()" (o qualunque altra cosa) e le passate una funzione che emette il messaggio di log (questa è la funzione di callback differita). "write ()" memorizza internamente un riferimento a una determinata funzione, inizia a scrivere sul file e imposta il proprio callback per sapere quando la scrittura è terminata. Quindi ritorna prima che la scrittura sia terminata; 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 registro.

La parte "differita" significa semplicemente che la funzione di richiamata non viene chiamata immediatamente; chiamarlo è rinviato al momento opportuno. Nel caso di funzioni asincrone come molte di quelle in node.js, il callback dato viene generalmente chiamato al termine dell'operazione (o si verifica un errore).

La maggior parte delle cose è asincrona in node.js, ma nel browser con ad esempio jQuery, la maggior parte delle cose è in realtà sincrona (tranne, ovviamente, per le richieste AJAX). Poiché le funzioni di prima classe sono così utili in JavaScript (soprattutto a causa dell'ottimo supporto di chiusura), i callback sono utilizzati anche ovunque nel browser, ma non sono "differiti" per le operazioni sincrone (tranne nella misura in cui non sono chiamati immediatamente da tu, ma più tardi dalla funzione che chiami).

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


8

Il modo in cui funziona una richiamata differita è ogni volta che si aggiunge una richiamata, tale richiamata viene trasferita a un array. Quindi, quando viene chiamato il metodo .resolve()o .resolveWith()sull'oggetto differito, tutti i .done()callback nell'array vengono eseguiti in ordine.

Ora possiamo vedere cos'è un oggetto differito. Prendi lo snippet di seguito come esempio.

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

Ciò che abbiamo ora è un oggetto differito e l'oggetto promesso dell'oggetto differito. L'oggetto differite ha 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 differita per ciascuna rispettiva event. L'oggetto differito d'altra parte ha molti altri metodi, soprattutto .resolve()e .reject(). Quando questi metodi vengono chiamati sull'oggetto differito, vengono chiamati tutti i callback. .resolve()attiva i callback .done()e .always()mentre il .reject()metodo chiama .fail()e .always()callbacks.

Generalmente l'oggetto differito 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 differito verrà risolto in seguito, ad esempio dopo il completamento di una richiesta Ajax o dopo il caricamento di un'immagine, dopo un setTimeout, ecc. È inoltre importante rendersi conto che un oggetto differito può essere risolto una sola volta. Se è già stato risolto, i callback verranno richiamati immediatamente.

Ecco un altro esempio, quello 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 $.Deferred()metodo di jQuery e sugli oggetti differiti, visitare http://api.jquery.com/category/deferred-object/


Questo probabilmente avrà un valore inestimabile una volta che avrò la testa sul concetto di una callback differita. Mi dispiace, ma ancora non capisco il concetto di cosa sia un callback differito. Sto più cercando l'idea concettuale dietro di essa. Un po 'lungo l'idea di Mihia. Una volta che riesco a farmi girare la testa, allora forse capisco js.
tentimes

3

Non sono sicuro, ma credo che un callback differito si riferisca a un callback asincrono, quindi avrai più fortuna a cercarlo su Google.

La migliore spiegazione che ho trovato è stata su http://www.nodebeginner.org

Ciao probabilmente questo callbackFunction () qui e chiamarlo quando hai finito di fare le tue cose costose? Grazie!"

In questo esempio, probabilmenteExpensiveFunction è 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 a un certo punto, deciderà di eseguire qualcosa dal loop 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 probabilmenteExExpensiveFunction puoi prendere fs.readFile


Grazie. Ma come farà la costosa funzione a fare cose se è già tornata e sei tornato nel thread principale dell'esecuzione? Non capisco. Stai dicendo che la funzione persiste in qualche modo dopo che finisce?

Modificata la risposta, forse ora è più chiara.

Molto utile. Ma ... devo elaborare questo array di callback memorizzati? Ciò che intendo è che cosa sta elaborando questo elenco. È (ad esempio) che js solleva questi callback in background senza che tu debba fare nulla al riguardo, o è che un evento provoca node.js o qualcosa che chiama un callback particolare. Mi dispiace, sto ottenendo circa il 70% di quello che stai dicendo, ma sono solo un po 'perso per il resto :)
tentimes

@tentimes - "cos'è che sta elaborando questo elenco" l'oggetto $ .Deferred () sta elaborando l'elenco. Quando si chiama .resolve()o .reject()sull'oggetto differito originale, viene chiamato l'elenco dei callback.
user400654

2
@tentimes: Da quello che stai dicendo, non sono sicuro che tu abbia completamente criticato il fatto che le funzioni in JS sono oggetti di prima classe, e quindi possono essere archiviate fino al momento in cui sono state create. Ad esempio dire che si desidera scrivere su un file, quindi stampare un messaggio di registro; così chiamate la funzione "write" (o qualunque altra cosa) e le passate una funzione che emette il messaggio di log. "write ()" memorizza internamente un riferimento a una determinata funzione, inizia a scrivere sul file e imposta il proprio callback per sapere quando la scrittura è terminata. Quindi ritorna prima che la scrittura sia terminata; quando lo è, viene chiamata la tua funzione.
Cameron,

3

JavaScript è a thread singolo, quindi non puoi pensare in termini di thread per capirlo. Ecco un esempio di callback sia normali che asincroni usando 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);

Ora questo mi sta portando da qualche parte, grazie. Quindi l'asincrono è in risposta a un evento che ho impostato con Ajax - che lo fa semplicemente uscire e se l'evento accade il mio callback viene chiamato? Penso di averlo capito. Node.js / jquery farebbe qualcosa di simile con jquery utilizzando oggetti rinviati e un complicato sistema di interazione con essi per fare esattamente la stessa cosa ma usando i metodi?
tentimes

1
@tentimes, esattamente! I callback di solito vengono eseguiti in risposta agli eventi (ma poiché "callback" non è un costrutto del linguaggio js, ​​a volte il termine viene utilizzato in altri contesti). Gli oggetti differiti (promesse) che vedi nella risposta di Kevin sono fondamentalmente zucchero sintattico. Vengono "risolti" o "rifiutati" quando viene attivato un evento (asincrono), quindi chiamano il callback appropriato ("completato" o "non riuscito", quindi "sempre"). Usarli in jQuery può rendere il codice più leggibile e consentire alcuni trucchi aggiuntivi (come aggiungere facilmente un secondo callback dopo aver lanciato una richiesta Ajax, per esempio).
bfavaretto,

Entrambi sono callback asincroni
Raynos

1

I callback differiti (aka Promices ) ti consentono di scrivere codice asincrono sequenziale, senza dolore e spaghetti di callback:

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

'when' ti consente di attendere che le funzioni tornino in parallelo e thenpossono essere concatenate in sequenza.

una nota: jQuery deferreds ! = Promices / A , la loro sintassi è un po 'diversa.

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


1
uhh ... si scopre - OP ha chiesto una cosa leggermente diversa ... beh, speriamo che questa risposta possa aiutare qualcun altro, un giorno, forse.
c69,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.