Comment attendre Qu'une promesse JavaScript se résolve avant de reprendre la fonction?

je fais des tests en unité. Le cadre d'essai charge une page dans une iFrame et exécute ensuite des assertions contre cette page. Avant chaque test commence, je crée un Promise qui définit l'iFrame onload événement à appeler resolve(), définit l'iFrame src, et renvoie la promesse.

alors, je peux juste appeler loadUrl(url).then(myFunc), et il faudra attendre que la page se charge avant l'exécution de tout ce myFunc est.

- je utiliser ce type de modèle partout dans mes tests (pas juste pour charger des URLs), principalement pour permettre des changements au DOM (par exemple, mimick cliquant sur un bouton, et attendre que divs se cache et s'affiche).

l'inconvénient de cette conception est que j'écris constamment des fonctions anonymes avec quelques lignes de code. En outre, pendant que j'ai un travail-autour (QUnit est assert.async()), la fonction de test qui définit les promesses se termine avant l'exécution de la promesse.

je me demande s'il y a un moyen d'obtenir une valeur d'un Promise ou attendre (bloquer/dormir) jusqu'à ce qu'il ait résolu, semblable à. NET IAsyncResult.WaitHandle.WaitOne(). Je sais que JavaScript est simple, mais j'espère que ça ne veut pas dire qu'une fonction ne peut pas céder.

essentiellement, y a-t-il un moyen d'obtenir ce qui suit pour brosser 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>
38
demandé sur dfoverdx 0000-00-00 00:00:00

1 réponses

je me demande s'il y a un moyen d'obtenir une valeur d'une promesse ou attendre (bloquer / dormir) jusqu'à ce qu'il ait résolu, similaire à .NET IAsyncResult.WaitHandle.WaitOne (). Je sais que JavaScript est mono-thread, mais j'espère que cela ne signifie pas qu'une fonction ne peut pas céder.

La génération actuelle de Javascript dans les navigateurs n'ont pas de wait() ou sleep() qui permet à d'autres choses à courir. 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 truc et vous appelleront quand ils auront fini (comme vous avez utilisé des promesses pour).

Ceci est en partie dû au fait que Javascript est un seul threadedness. Si le fil simple tourne, alors aucun autre Javascript ne peut s'exécuter jusqu'à ce que ce fil soit terminé. ES6 introduit yield et les générateurs qui permettront quelques astuces coopératives comme cela, mais nous sommes assez loin d'être en mesure d'utiliser ceux-ci dans un large éventail de navigateurs installés (ils peut être utilisé dans certains développements côté serveur où vous contrôlez le moteur JS qui est utilisé).


Attention, la gestion de la promesse code pouvez contrôler l'ordre d'exécution d'un ensemble d'opérations asynchrones.

Je ne suis pas sûr de comprendre exactement quel ordre vous essayez d'atteindre dans votre code, mais vous pourriez faire quelque chose comme ça en utilisant votre existant kickoff() fonction et ensuite seulement attacher un .then() gestionnaire après l'appel de c':

function kickOff() {
  return new Promise(function(resolve, reject) {
    $("#output").append("start");

    setTimeout(function() {
      resolve();
    }, 1000);
  }).then(function() {
    $("#output").append(" middle");
    return " end";
  });
}

kickoff().then(function(result) {
    // use the result here
    $("#output").append(result);
});

cela vous donnera une sortie comme celle-ci dans un ordre garanti:

start
middle
end

mise à jour en 2018 (trois ans après cette réponse a été écrite):

si vous transférez votre code ou exécutez votre code dans un environnement qui supporte les fonctionnalités ES7 telles que async et await, vous pouvez maintenant utiliser await faire "apparaître" votre code pour attendre le résultat d'une promesse. Elle se développe encore avec des promesses. Il n'a pas encore bloquez tout Javascript, mais cela vous permet d'écrire des opérations séquentielles dans une syntaxe plus conviviale.

au lieu de la façon ES6 de faire les choses:

someFunc().then(someFunc2).then(result => {
    // process result here
}).catch(err => {
    // process error here
});

Vous pouvez faire ceci:

// returns a promise
async function wrapperFunc() {
    try {
        let r1 = await someFunc();
        let r2 = await someFunc2(r1);
        // now process r2
        return someValue;     // this will be resolved value of the returned promise
    } catch(e) {
        console.log(e);
        throw e;      // let caller know the promise rejected with this reason
    }
}

wrapperFunc().then(result => {
    // got final result
}).catch(err => {
    // got error
});
28
répondu jfriend00 2018-03-18 16:41:23