En JavaScript, l'utilisation de ' await` dans une boucle bloque-t-elle la boucle?

Prenez la boucle suivante:

for(var i=0; i<100; ++i){
    let result = await some_slow_async_function();
    do_something_with_result();
}
  1. await bloque-t-il la boucle? Ou le i continue-t-il à être incrémenté pendant que awaiting?

  2. L'ordre de do_something_with_result() est-il garanti séquentiel par rapport à i? Ou dépend-il de la vitesse de la fonction awaited pour chaque i?

24
demandé sur Bergi 2017-06-07 13:29:58

3 réponses

  1. await bloque-t-il la boucle? Ou le i continue-t-il à être incrémenté pendant que awaiting?

"Bloc" n'est pas le bon mot, mais oui, , je ne pas continuer à être incrémenté en attendant. Au lieu de cela, l'exécution revient à l'endroit où la fonction async a été appelée, fournissant une promesse comme valeur de retour, continuant le reste du code qui suit après l'appel de la fonction, jusqu'à ce que la pile de code ait été vidée. Puis quand l'attente est terminée, l'état de la fonction est restauré et l'exécution se poursuit dans cette fonction. Chaque fois que cette fonction retourne (complète), la promesse correspondante-qui a été renvoyée plus tôt-est résolue.

  1. L'ordre de do_something_with_result() est-il garanti séquentiel par rapport à i? Ou dépend-il de la vitesse de la fonction awaited pour chaque i?

L'ordre est garanti. Le code suivant le await est également garanti pour exécuter seulement après le la pile d'appels a été vidée, c'est-à-dire au moins sur ou après l'exécution de la prochaine microtask.

Voir comment la sortie est dans cet extrait. Notez surtout où il est dit "Après avoir appelé test":

async function test() {
    for (let i = 0; i < 2; i++) {
        console.log('Before await for ', i);
        let result = await Promise.resolve(i);
        console.log('After await. Value is ', result);
    }
}

test().then(_ => console.log('After test() resolved'));

console.log('After calling test');
26
répondu trincot 2017-06-07 10:53:55

Comme le dit @realbart, il bloque la boucle, ce qui rendra les appels séquentiels.

Si vous voulez déclencher une tonne d'opérations attendues et les gérer toutes ensemble, vous pouvez faire quelque chose comme ceci:

const promisesToAwait = [];
for (let i = 0; i < 100; i++) {
  promisesToAwait.push(fetchDataForId(i));
}
const responses = await Promise.all(promisesToAwait);
5
répondu Kris Selbekk 2017-06-07 10:44:52

Vous pouvez tester async / await dans une boucle " FOR " comme ceci:

(async  () => {
        for (let i = 0; i < 100; i++) {
                await delay();
                console.log(i);
        }
})();

function delay() {
        return new Promise((resolve, reject) => {
                setTimeout(resolve, 100);
        });
}
4
répondu mzalazar 2017-09-07 15:55:03