Que sont les rappels différés?

15

Je comprends l'idée d'un rappel, où je passe une fonction dans une autre fonction et cette fonction utilise ensuite la fonction fournie à volonté.

J'ai du mal à comprendre les rappels différés, même après avoir effectué une recherche sur Google.

Quelqu'un pourrait-il fournir une explication simple s'il vous plaît? Je programme en Ruby, mais je connais aussi un peu le C / C ++, mais surtout j'étais un programmeur de langage assembleur expérimenté. Je me demande donc si c'est un peu comme une pile d'adresses de rappel qui apparaissent. J'espère apprendre jquery ou node.js et ces rappels différés semblent faire partie intégrante des deux. Je comprends les principes de base du filetage (bien qu'un objet mutex me fasse mal à la tête;)

dix fois
la source
Voulez-vous dire les Deferredobjets de jQuery ? S'agit-il de quelque chose de spécifique à Node.js?
bfavaretto
1
Non, je veux dire en général. Bien que je veuille apprendre jquery et éventuellement node.js, je sentais que j'avais besoin de comprendre ce qu'est en fait un rappel différé. J'ai lu l'article Wikipedia sur les rappels, mais je n'ai pas pu comprendre les rappels différés, qui semblent intrinsèques au paradigme du fonctionnement asynchrone qui sera impliqué dans ces langages qui l'utilisent.
1
Je demande vraiment l'idée conceptuelle du rappel différé par opposition à leur mise en œuvre - désolé si je n'ai pas précisé cela. J'ai donné des exemples de langue plus pour expliquer l'idée que j'essaie de clarifier et aussi mon expérience en programmation afin que les gens sachent comment présenter la réponse. Merci beaucoup pour les réponses jusqu'à présent - j'y arrive!
tentimes
Ok je pense que je l'ai maintenant les gars, merci à vous tous! Je ne sais pas comment faire la réponse. Cameron a expliqué le concept de la manière la plus simple et c'est ce que je recherchais vraiment, mais d'autres sont également intervenus et ont enrichi mes connaissances. Je ne sais pas comment accepter la réponse car je suis nouveau dans ce domaine;)
dix fois le

Réponses:

4

Sur demande, voici les commentaires présentés en réponse:


Je ne suis pas sûr que vous compreniez complètement le fait que les fonctions dans JS sont des objets de première classe, et peuvent donc être stockées jusqu'à ce qu'elles soient nécessaires, après leur création.

Par exemple, supposons que vous souhaitiez écrire dans un fichier, puis imprimez un message de journal; vous appelez donc la fonction "write ()" (ou autre) et lui transmettez une fonction qui génère le message de journal (il s'agit de la fonction de rappel différé). "write ()" stocke en interne une référence à la fonction donnée, commence à écrire dans le fichier et configure son propre rappel pour savoir quand l'écriture est terminée. Il revient ensuite avant que l'écriture ne soit terminée; quand c'est le cas, le rappel interne est en quelque sorte appelé (c'est le travail du framework sous-jacent - dans le cas de node.js, c'est fait avec une boucle d'événement), qui appelle ensuite votre rappel qui imprime le message du journal.

La partie "différée" signifie simplement que votre fonction de rappel n'est pas appelée immédiatement; l'appel est différé jusqu'au moment approprié. Dans le cas de fonctions asynchrones comme beaucoup de celles de node.js, le rappel donné est généralement appelé à la fin de l'opération (ou une erreur se produit).

La plupart des trucs sont asynchrones dans node.js, mais dans le navigateur avec par exemple jQuery, la plupart des trucs sont en fait synchrones (sauf, évidemment, pour les requêtes AJAX). Étant donné que les fonctions de première classe sont si pratiques en JavaScript (en particulier en raison de la grande prise en charge de la fermeture), les rappels sont également utilisés partout dans le navigateur, mais ils ne sont pas "différés" pour les opérations synchrones (sauf dans la mesure où ils ne sont pas appelés immédiatement par vous, mais plus tard par la fonction que vous appelez).

Le fait que le système sous-jacent soit piloté par les événements est orthogonal à l'utilisation de rappels différés; vous pouvez imaginer une version (très lente) de node.js qui a démarré un thread pour chaque opération, puis a appelé votre rappel donné lorsque le thread a terminé son travail, sans utiliser d'événements du tout. Bien sûr, c'est un modèle horrible, mais il illustre mon point :-)

Cameron
la source
8

Le fonctionnement d'un rappel différé est chaque fois que vous lui ajoutez un rappel, ce rappel est poussé vers un tableau. Ensuite, lorsque la méthode .resolve()or .resolveWith()est appelée sur l'objet différé, tous les .done()rappels du tableau sont exécutés dans l'ordre.

Maintenant, nous pouvons voir ce qu'est un objet différé. Prenez l'exemple ci-dessous.

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

Ce que nous avons maintenant est un objet différé, et l'objet promis de l'objet différé. L'objet différé a tout cependant l'objet de promesse n'a que les méthodes les mêmes méthodes que l'objet de la promesse, .done(), .fail()et .always()qui sont utilisés pour ajouter des callbacks à l'objet différé pour chaque respectif event. L'objet différé d'autre part a plusieurs autres méthodes, le plus important .resolve()et .reject(). Lorsque ces méthodes sont appelées sur l'objet différé, tous les rappels sont appelés. .resolve()déclenche les rappels .done()et .always()tandis que la .reject()méthode appelle .fail()et rappelle .always().

Généralement, l'objet différé est conservé caché dans une portée privée et l'objet de promesse est renvoyé par la fonction afin que des rappels puissent y être placés. L'objet différé sera résolu plus tard, par exemple après qu'une requête ajax est terminée ou après le chargement d'une image, après un setTimeout, etc. Il est également important de réaliser qu'un objet différé ne peut être résolu qu'une seule fois. S'il est déjà résolu, ses rappels seront appelés immédiatement.

Voici un autre exemple, celui que j'utilise:

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!");
});

Pour plus d'informations sur la $.Deferred()méthode de jQuery et les objets différés, visitez http://api.jquery.com/category/deferred-object/

user400654
la source
Ce sera probablement inestimable une fois que j'aurai pensé à la notion de rappel différé. Désolé, mais je ne comprends toujours pas le concept de ce qu'est un rappel différé. Je cherche plus l'idée conceptuelle derrière. En quelque sorte l'idée de Mihia. Une fois que je pourrai tourner la tête, je pourrai peut-être comprendre js.
tentimes
3

Je ne suis pas sûr, mais je crois qu'un rappel différé fait référence à un rappel asynchrone, vous aurez donc plus de chance de google pour cela.

La meilleure explication que j'ai trouvée était sur http://www.nodebeginner.org

Hé, probablementExpensiveFunction (), veuillez faire votre travail, mais moi, le seul thread Node.js, je ne vais pas attendre ici jusqu'à ce que vous ayez terminé, je continuerai à exécuter les lignes de code en dessous de vous, alors veuillez prendre cette fonction de rappel () ici et l'appeler lorsque vous avez fini de faire vos trucs chers? Merci!"

Dans cet exemple, probablementExpensiveFunction est une fonction non bloquante (ou asynchrone). Cela signifie qu'il n'est pas exécuté immédiatement, mais placé dans une soi-disant boucle d'événements. Le thread node.js continuera son exécution, mais à un moment donné, il décidera d'exécuter quelque chose à partir de la boucle d'événements. Quand il atteint probablementExpensiveFunction, il l'appelle et quand probablementExpensiveFunction termine l'exécution, il appelle le rappel (différé) passé en tant que paramètre.

À titre d'exemple de probablementExpensiveFunction, vous pouvez prendre fs.readFile

mihai
la source
Merci. Mais comment la fonction coûteuse va-t-elle faire son travail si elle est déjà revenue et que vous êtes de retour dans le thread principal d'exécution? Je ne comprends pas ce morceau. Voulez-vous dire que la fonction persiste d'une manière ou d'une autre après sa fin?
Modifié la réponse, peut-être que c'est plus clair maintenant.
Très utile. Mais ... dois-je traiter ce tableau de rappels stockés? Ce que je veux dire, c'est ce qui traite cette liste. Est-ce (par exemple) que js soulève ces rappels en arrière-plan sans que vous ayez à y faire quoi que ce soit, ou est-ce qu'un événement fait que node.js ou quelque chose appelle un rappel particulier. Désolé, je reçois environ 70% de ce que vous dites mais je suis juste un peu perdu sur le reste :)
dix fois le
@tentimes - "qu'est-ce qui traite cette liste" l'objet $ .Deferred () traite la liste. Lorsque vous appelez .resolve()ou .reject()sur l'objet différé d'origine, la liste des rappels est appelée.
user400654
2
@tentimes: D'après ce que vous dites, je ne suis pas sûr que vous compreniez complètement le fait que les fonctions dans JS sont des objets de première classe, et peuvent donc être stockées jusqu'à ce qu'elles soient nécessaires, après leur création. Par exemple, dites que vous voulez écrire dans un fichier, puis imprimez un message de journal; vous appelez donc la fonction "écriture" (ou autre) et lui passez une fonction qui génère le message du journal. "write ()" stocke en interne une référence à la fonction donnée, commence à écrire dans le fichier et configure son propre rappel pour savoir quand l'écriture est terminée. Il revient ensuite avant que l'écriture ne soit terminée; quand c'est le cas, votre fonction est appelée.
Cameron
3

JavaScript est un thread unique, vous ne pouvez donc pas penser en termes de threads pour comprendre cela. Voici un exemple de rappels réguliers et asynchrones utilisant 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);
bfavaretto
la source
Maintenant, cela me mène quelque part, merci. Donc, l'asynchrone est en réponse à un événement que j'ai configuré avec ajax - qui le ferme et si l'événement se produit, mon rappel est appelé? Je pense que je comprends. Est-ce que node.js / jquery ferait quelque chose de similaire avec jquery usnig objets différés et un système compliqué d'interaction avec eux pour vraiment faire la même chose mais en utilisant des méthodes?
tentimes
1
@tentimes, exactement! Les rappels s'exécutent généralement en réponse à des événements (mais comme «rappel» n'est pas une construction de langage js, le terme est parfois utilisé dans d'autres contextes). Les objets différés (promesses) que vous voyez dans la réponse de Kevin sont essentiellement du sucre syntaxique. Ils sont «résolus» ou «rejetés» lorsqu'un événement (asynchrone) est déclenché, puis ils appellent le rappel approprié («terminé» ou «échec», puis «toujours»). Les utiliser dans jQuery peut rendre le code plus lisible et permet des astuces supplémentaires (comme ajouter facilement un deuxième rappel après avoir lancé une requête ajax, par exemple).
bfavaretto
Les deux sont des rappels asynchrones
Raynos
1

Les rappels différés (alias Promises ) vous permettent d'écrire du code asynchrone séquentiel, sans douleur ni spaghetti de rappel:

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

'quand' vous permet d'attendre le retour des fonctions en parallèle et thenpeut être enchaîné séquentiellement.

une remarque: jQuery différé ! = Promises / A , leur syntaxe est un peu différente.

Il y a de bons articles sur le sujet: un sur IEBlog et un autre dans un blog aléatoire , un livre et une question de stackoverflow populaire

c69
la source
1
euh .. il se trouve - OP a demandé quelque chose de légèrement différent ... eh bien, espérons que cette réponse aidera quelqu'un d'autre, un jour, peut-être.
c69