Je fais des tests unitaires. Le framework de test charge une page dans un iFrame, puis exécute des assertions sur cette page. Avant le début de chaque test, je crée un Promise
qui définit l' onload
événement de l'iFrame à appeler resolve()
, définit l'iFrame src
et renvoie la promesse.
Donc, je peux simplement appeler loadUrl(url).then(myFunc)
, et il attendra que la page se charge avant d'exécuter quoi que ce myFunc
soit.
J'utilise ce type de modèle partout dans mes tests (pas seulement pour charger des URL), principalement pour permettre aux modifications du DOM de se produire (par exemple, imiter en cliquant sur un bouton, et attendre que les divs se masquent et s'affichent).
L'inconvénient de cette conception est que j'écris constamment des fonctions anonymes contenant quelques lignes de code. De plus, même si j'ai une solution de contournement (QUnit assert.async()
), la fonction de test qui définit les promesses se termine avant que la promesse ne soit exécutée.
Je me demande s'il existe un moyen d'obtenir une valeur de a Promise
ou d'attendre (bloquer / dormir) jusqu'à ce qu'il soit résolu, similaire à .NET IAsyncResult.WaitHandle.WaitOne()
. Je sais que JavaScript est monothread, mais j'espère que cela ne signifie pas qu'une fonction ne peut pas céder.
En gros, y a-t-il un moyen d'obtenir les résultats suivants pour recracher les résultats dans le bon ordre?
function kickOff() {
return new Promise(function(resolve, reject) {
$("#output").append("start");
setTimeout(function() {
resolve();
}, 1000);
}).then(function() {
$("#output").append(" middle");
return " end";
});
};
function getResultFrom(promise) {
// todo
return " end";
}
var promise = kickOff();
var result = getResultFrom(promise);
$("#output").append(result);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="output"></div>
la source
.then(fnAppend.bind(myDiv))
, ce qui peut réduire considérablement les anons.Réponses:
La génération actuelle de Javascript dans les navigateurs n'a pas de
wait()
ousleep()
qui permet à d'autres choses de fonctionner. Donc, vous ne pouvez tout simplement pas faire ce que vous demandez. Au lieu de cela, il a des opérations asynchrones qui feront leur travail, puis vous appelleront quand elles auront terminé (comme vous avez utilisé les promesses pour).Ceci est en partie dû au threading unique de Javascript. Si le thread unique tourne, aucun autre Javascript ne peut s'exécuter tant que ce thread ne tourne pas. ES6 introduit
yield
et générateurs qui permettront certaines astuces coopératives comme celle-ci, mais nous sommes assez loin de pouvoir les utiliser dans un large éventail de navigateurs installés (ils peuvent être utilisés dans certains développements côté serveur où vous contrôlez le moteur JS qui est utilisé).Une gestion attentive du code basé sur la promesse peut contrôler l'ordre d'exécution de nombreuses opérations asynchrones.
Je ne suis pas sûr de comprendre exactement l'ordre que vous essayez d'obtenir dans votre code, mais vous pouvez faire quelque chose comme ça en utilisant votre
kickOff()
fonction existante , puis en y attachant un.then()
gestionnaire après l'avoir appelé:Cela renverra la sortie dans un ordre garanti - comme ceci:
Mise à jour en 2018 (trois ans après la rédaction de cette réponse):
Si vous transpilez votre code ou exécutez votre code dans un environnement qui prend en charge les fonctionnalités ES7 telles que
async
etawait
, vous pouvez maintenant utiliserawait
pour faire "apparaître" votre code pour attendre le résultat d'une promesse. Il se développe toujours avec des promesses. Il ne bloque toujours pas tout Javascript, mais il vous permet d'écrire des opérations séquentielles dans une syntaxe plus conviviale.Au lieu de la façon de faire ES6:
Tu peux le faire:
la source
then()
est ce que j'ai fait. Je n'aime pas avoir à écrirefunction() { ... }
tout le temps. Cela encombre le code.(foo) => { ... }
au lieu defunction(foo) { ... }
foo => single.expression(here)
pour vous débarrasser des crochets bouclés et ronds.async
et laawait
syntaxe en option qui est maintenant disponible dans node.js et dans les navigateurs modernes ou via des transpilers.Si vous utilisez ES2016 vous pouvez utiliser
async
etawait
faire quelque chose comme:Si vous utilisez ES2015, vous pouvez utiliser des générateurs . Si vous n'aimez pas la syntaxe, vous pouvez la résumer en utilisant une
async
fonction utilitaire comme expliqué ici .Si vous utilisez ES5, vous voudrez probablement une bibliothèque comme Bluebird pour vous donner plus de contrôle.
Enfin, si votre environnement d'exécution prend en charge ES2015, l'ordre d'exécution peut être conservé avec le parallélisme à l'aide de Fetch Injection .
la source
async
/await
.async
/await
est juste une autre syntaxe pourPromise.then
.async
ne pas attendre ... à moins que cela ne cède à l' utilisationawait
. L'exemple ES2016 / ES7 ne peut toujours pas être exécuté SO alors voici un code que j'ai écrit il y a trois ans pour démontrer le comportement.Une autre option consiste à utiliser Promise.all pour attendre la résolution d'un ensemble de promesses. Le code ci-dessous montre comment attendre que toutes les promesses se résolvent, puis traiter les résultats une fois qu'ils sont tous prêts (car cela semblait être l'objectif de la question); Cependant, start pourrait évidemment sortir avant que middle ait résolu simplement en ajoutant ce code avant d'appeler résoudre.
la source
Vous pouvez le faire manuellement. (Je sais que ce n'est pas une bonne solution, mais ..) utilisez la
while
boucle jusqu'à ce que leresult
n'ait pas de valeurla source