153 votes

Comment créer une fonction asynchrone en Javascript ?

Regarde ça code :

<a href="#" id="link">Link</a>
<span>Moving</span>

$('#link').click(function () {
    console.log("Enter");
    $('#link').animate({ width: 200 }, 2000, function() {
         console.log("finished");            
    });    
    console.log("Exit");    
});

Comme vous pouvez le voir dans la console, la fonction "animate" est asynchrone, et elle "bifurque" le flux de code du bloc du gestionnaire d'événement. En effet :

$('#link').click(function () {
    console.log("Enter");
    asyncFunct();
    console.log("Exit");    
});

function asyncFunct() {
    console.log("finished");
}

suivez le flux du code-bloc !

Si je souhaite créer mon function asyncFunct() { } avec ce comportement, comment puis-je le faire avec javascript/jquery ? Je pense qu'il existe une stratégie sans l'utilisation de setTimeout()

0 votes

Jetez un coup d'œil aux sources de jQuery :)

0 votes

Le mathod .animate() utilise un callback. Animate appellera la callback lorsque l'animation sera terminée. Si vous souhaitez obtenir le même comportement que .animate(), vous avez besoin d'un callback (appelé par la fonction "main" après d'autres opérations). C'est différent si vous avez besoin d'une fonction asynchrone "complète" (une fonction appelée sans bloquer le flux d'exécution). Dans ce cas, vous pouvez utiliser setTimeout() avec un délai proche de 0.

0 votes

@Fabio Buda : pourquoi callback() devrait implémenter une sorte d'asynchrone ? En fait, ce n'est pas le cas jsfiddle.net/5H9XT/9

190voto

pimvdb Points 66332

Vous ne pouvez pas créer une fonction asynchrone vraiment personnalisée. Vous devrez éventuellement vous appuyer sur une technologie fournie nativement, telle que :

  • setInterval
  • setTimeout
  • requestAnimationFrame
  • XMLHttpRequest
  • WebSocket
  • Worker
  • Certaines API HTML5, telles que l'API fichier, l'API base de données Web, etc.
  • Les technologies qui soutiennent onload
  • ... beaucoup d'autres

En fait, pour l'animation, jQuery utilise setInterval .

3 votes

Je discutais de cela avec un ami hier, alors cette réponse est parfaite ! Je comprends et je peux identifier les fonctions asynchrones et les utiliser correctement en JS. Mais simplement pourquoi ne pouvons-nous pas en mettre en place des personnalisés n'est pas clair pour moi. C'est comme une boîte noire dont nous savons comment la faire fonctionner (en utilisant, par exemple, setInterval ) mais que nous ne pouvons même pas l'ouvrir pour voir comment il est fait. Auriez-vous plus d'informations à ce sujet ?

2 votes

@MatheusFelipe ces fonctions sont natives de l'implémentation du moteur javascript et la seule chose à laquelle vous pouvez vous fier sont les spécifications, Par exemple, les minuteurs HTML5 et faire confiance à la nature de la boîte noire qui se comporte selon les spécifications.

10 votes

@MatheusFelipe youtu.be/8aGhZQkoFbQ le meilleur exposé à ce jour sur ce sujet...

74voto

Šime Vidas Points 59994

Vous pouvez utiliser un minuteur :

setTimeout( yourFn, 0 );

(où yourFn est une référence à votre fonction)

ou, avec Lodash :

_.defer( yourFn );

Diffère l'invocation de la func jusqu'à ce que la pile d'appels actuelle soit effacée. Tout argument supplémentaire est fourni à func lorsqu'il est invoqué.

3 votes

Cela ne fonctionne pas, ma fonction javascript qui dessine dans un canevas fait que l'interface utilisateur ne répond pas.

4 votes

@gab06 - Je dirais que la fonction de dessin de votre toile se bloque pour ses propres bonnes raisons. Divisez son action en plusieurs petites actions et invoquez chacune d'entre elles avec une minuterie : vous verrez que l'interface réagit ainsi aux clics de souris, etc.

1 votes

Temps minimum pour setTimeout est de 4 millisecondes selon la spécification HTML5. Si vous lui donnez 0, cela prendra quand même ce temps minimum. Mais oui, cela fonctionne bien comme un différateur de fonction.

30voto

fider Points 226

Ici vous avez une solution simple (d'autres écrivent à ce sujet) http://www.benlesh.com/2012/05/calling-javascript-function.html

Et ici vous avez la solution prête ci-dessus :

function async(your_function, callback) {
    setTimeout(function() {
        your_function();
        if (callback) {callback();}
    }, 0);
}

TEST 1 ( peut produire '1 x 2 3' ou '1 2 x 3' ou '1 2 3 x'. ):

console.log(1);
async(function() {console.log('x')}, null);
console.log(2);
console.log(3);

TEST 2 ( produira toujours 'x 1'. ):

async(function() {console.log('x');}, function() {console.log(1);});

Cette fonction est exécutée avec un délai d'attente de 0 - elle simule une tâche asynchrone.

7 votes

Le TEST 1 ne peut en fait produire que '1 2 3 x' et le TEST 2 est assuré de produire '1 x' à chaque fois. La raison de ces résultats inattendus dans le TEST 2 est que console.log(1) est appelé et la sortie ( undefined ) est passé comme deuxième argument à async() . Dans le cas du TEST 1, je pense que vous ne comprenez pas bien la file d'attente d'exécution de JavaScript. Parce que chacun des appels à console.log() se produisent dans la même pile, x est garantie d'être enregistrée en dernier. Je voterais bien cette réponse pour cause de désinformation, mais je n'ai pas assez de représentants.

1 votes

Joshua : Il semble que @fider voulait écrire TEST 2 comme : async(function() {console.log('x')}, function(){console.log(1)}); .

0 votes

Oui @nzn et @Joshua je voulais dire TEST 2 as: async(function() {console.log('x')}, function(){console.log(1)}); - Je l'ai déjà corrigé

10voto

Ethan McTague Points 650

Voici une fonction qui prend une autre fonction et produit une version qui s'exécute de manière asynchrone.

var async = function (func) {
  return function () {
    var args = arguments;
    setTimeout(function () {
      func.apply(this, args);
    }, 0);
  };
};

Il est utilisé comme un moyen simple de créer une fonction asynchrone :

var anyncFunction = async(function (callback) {
    doSomething();
    callback();
});

C'est différent de la réponse de @fider parce que la fonction elle-même a sa propre structure (pas de callback ajouté, c'est déjà dans la fonction) et aussi parce que cela crée une nouvelle fonction qui peut être utilisée.

0 votes

SetTimeout ne peut pas être utilisé dans une boucle (appeler plusieurs fois la même fonction avec des arguments distincts) .

0 votes

@user2284570 C'est à ça que servent les fermetures. (function(a){ asyncFunction(a); })(a)

1 votes

IIRC, vous pouvez également réaliser cela sans fermeture : setTimeout(asyncFunction, 0, a);

6voto

Linus G Thiel Points 18378

Edit : J'ai totalement mal compris la question. Dans le navigateur, j'utiliserais setTimeout . S'il était important qu'il soit publié dans un autre fil, j'utiliserais Travailleurs du Web .

1 votes

? Cela ne fait pas une fonction asynchrone :O

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X