J'ai deux fonctions JS. L'un appelle l'autre. Dans la fonction d'appel, j'aimerais appeler l'autre, attendre que cette fonction se termine, puis continuer. Donc, par exemple / pseudo code:
function firstFunction(){
for(i=0;i<x;i++){
// do something
}
};
function secondFunction(){
firstFunction()
// now wait for firstFunction to finish...
// do something else
};
J'ai trouvé cette solution, mais je ne sais pas si c'est une façon intelligente de s'y prendre.
var isPaused = false;
function firstFunction(){
isPaused = true;
for(i=0;i<x;i++){
// do something
}
isPaused = false;
};
function secondFunction(){
firstFunction()
function waitForIt(){
if (isPaused) {
setTimeout(function(){waitForIt()},100);
} else {
// go do that thing
};
}
};
Est-ce légitime? Y a-t-il une manière plus élégante de le gérer? Peut-être avec jQuery?
firstFunction
ce que fait exactement qui le rend asynchrone? De toute façon - Vérifiez les promessesRéponses:
Une façon de gérer un travail asynchrone comme celui-ci est d'utiliser une fonction de rappel, par exemple:
Selon la suggestion de @Janaka Pushpakumara, vous pouvez désormais utiliser les fonctions fléchées pour réaliser la même chose. Par exemple:
firstFunction(() => console.log('huzzah, I\'m done!'))
Mise à jour: j'ai répondu à cela il y a un certain temps et je veux vraiment le mettre à jour. Bien que les rappels soient tout à fait corrects, d'après mon expérience, ils ont tendance à produire du code plus difficile à lire et à maintenir. Il y a des situations où je les utilise encore, par exemple pour passer des événements en cours, etc., en tant que paramètres. Cette mise à jour est juste pour souligner les alternatives.
De plus, la question d'origine ne mentionne pas spécifiquement async, donc au cas où quelqu'un serait confus, si votre fonction est synchrone, elle se bloquera lorsqu'elle sera appelée. Par exemple:
Si, comme implicite, la fonction est asynchrone, la façon dont j'ai tendance à gérer tout mon travail asynchrone aujourd'hui est async / await. Par exemple:
IMO, async / await rend votre code beaucoup plus lisible que d'utiliser directement les promesses (la plupart du temps). Si vous devez gérer des erreurs de capture, utilisez-le avec try / catch. En savoir plus ici: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function .
la source
Utilisez async / await:
puis utilisez await dans votre autre fonction pour attendre son retour:
la source
$(function() { await firstFunction(); secondFunction(); });
,?await
qu'il ne peut être utilisé qu'à l'intérieur d'uneasync
méthode. Donc, si vous faites fonctionner votre parent,async
vous pouvez en appeler autant à l'async methods
intérieurawait
que vous le souhaitez.await
unsetTimeout
?Il semble qu'il vous manque un point important ici: JavaScript est un environnement d'exécution à un seul thread. Regardons à nouveau votre code, notez que j'ai ajouté
alert("Here")
:Vous n'avez pas à attendre
isPaused
. Lorsque vous voyez l'alerte "Ici",isPaused
serafalse
déjà, etfirstFunction
sera de retour. C'est parce que vous ne pouvez pas "céder" de l'intérieur de lafor
boucle (// do something
), la boucle ne peut pas être interrompue et devra d'abord se terminer complètement (plus de détails: gestion des threads Javascript et conditions de course ).Cela dit, vous pouvez toujours faire en sorte que le code circule à l'intérieur
firstFunction
pour être asynchrone et utiliser un rappel ou une promesse pour notifier l'appelant. Vous devrez abandonner lafor
boucle et la simuler avec à laif
place ( JSFiddle ):Par ailleurs, JavaScript 1.7 a introduit le
yield
mot-clé dans le cadre des générateurs . Cela permettra de "percer" des trous asynchrones dans un flux de code JavaScript autrement synchrone ( plus de détails et un exemple ). Cependant, le support du navigateur pour les générateurs est actuellement limité à Firefox et Chrome, AFAIK.la source
Une manière élégante d'attendre qu'une fonction soit terminée en premier est d'utiliser Promises avec la fonction async / await .
setTimeout
pour démontrer la situation où les instructions prendraient un certain temps à s'exécuter.await
la première fonction avant de suivre les instructions.Exemple:
Remarque:
Vous pouvez simplement
resolve
lePromise
sans aucune valeur comme çaresolve()
. Dans mon exemple, jeresolved
lePromise
avec la valeur dey
que je peux ensuite utiliser dans la deuxième fonction.la source
Le seul problème avec les promesses est que IE ne les prend pas en charge. Edge le fait, mais il y a beaucoup d'IE 10 et 11 là-bas: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise (compatibilité en bas)
Donc, JavaScript est monothread. Si vous n'effectuez pas d'appel asynchrone, il se comportera de manière prévisible. Le thread JavaScript principal exécutera une fonction complètement avant d'exécuter la suivante, dans l'ordre dans lequel elles apparaissent dans le code. Garantir l'ordre des fonctions synchrones est trivial - chaque fonction s'exécutera complètement dans l'ordre dans lequel elle a été appelée.
Considérez la fonction synchrone comme une unité atomique de travail . Le thread JavaScript principal l'exécutera entièrement, dans l'ordre dans lequel les instructions apparaissent dans le code.
Mais, lancez l'appel asynchrone, comme dans la situation suivante:
Cela ne fait pas ce que vous voulez . Il exécute instantanément la fonction 1, la fonction 2 et la fonction 3. Le chargement de div clignote et il est parti, alors que l'appel ajax n'est pas presque terminé, même s'il
makeAjaxCall()
est retourné. LA COMPLICATION est qu'ilmakeAjaxCall()
a brisé son travail en morceaux qui sont avancés petit à petit à chaque rotation du thread JavaScript principal - il se comporte de manière asychronique. Mais ce même thread principal, pendant un spin / run, a exécuté les parties synchrones rapidement et de manière prévisible.Donc, la façon dont je l'ai géré : comme je l'ai dit, la fonction est l'unité atomique de travail. J'ai combiné le code de la fonction 1 et 2 - J'ai mis le code de la fonction 1 dans la fonction 2, avant l'appel asynchrone. Je me suis débarrassé de la fonction 1. Tout jusqu'à et y compris l'appel asynchrone s'exécute de manière prévisible, dans l'ordre.
ALORS, lorsque l'appel asynchrone se termine, après plusieurs tours du thread JavaScript principal, faites-lui appeler la fonction 3. Cela garantit l'ordre . Par exemple, avec ajax, le gestionnaire d'événements onreadystatechange est appelé plusieurs fois. Lorsqu'il signale qu'il est terminé, appelez la fonction finale souhaitée.
Je suis d'accord que c'est plus compliqué. J'aime que le code soit symétrique, j'aime que les fonctions fassent une chose (ou s'en rapprochent), et je n'aime pas que l'appel ajax soit en aucune façon responsable de l'affichage (créant une dépendance sur l'appelant). MAIS, avec un appel asynchrone incorporé dans une fonction synchrone, des compromis doivent être faits pour garantir l'ordre d'exécution. Et je dois coder pour IE 10 donc pas de promesses.
Résumé : Pour les appels synchrones, garantir l'ordre est trivial. Chaque fonction s'exécute entièrement dans l'ordre dans lequel elle a été appelée. Pour une fonction avec un appel asynchrone, le seul moyen de garantir l'ordre est de surveiller la fin de l'appel asynchrone et d'appeler la troisième fonction lorsque cet état est détecté.
Pour une discussion sur les fils JavaScript, voir: https://medium.com/@francesco_rizzi/javascript-main-thread-dissected-43c85fce7e23 et https://developer.mozilla.org/en-US/docs/Web/JavaScript/ EventLoop
Aussi, une autre question similaire et très appréciée à ce sujet: comment appeler 3 fonctions pour les exécuter l'une après l'autre?
la source
C'est ce que j'ai imaginé, car je dois exécuter plusieurs opérations dans une chaîne.
la source
Votre plaisir principal s'appellera firstFun, puis votre prochain plaisir appellera.
la source