2017-09-15 1 views
0

J'ai la fonction suivante. Il obtient un tableau d'attributs et les itère en boucle pour placer chaque attribut dans une base de données. Mais la boucle sera tué automatiquement avec la déclaration await:Pourquoi "attendre" casser ou tuer une boucle for-moderne en Javascript?

async function importAttributeRecords(attributeValues, languageId, attributes, dataStorage, tx) { 
    for(let attr of attributes) { 
    console.log("Persist", attr) 
    try { 
     await importAttributeRecord(attributeValues, languageId, attr, dataStorage, tx) 
    } 
    catch(err) { 
     console.log(err); 
    } 
    console.log("After persisting"); 
    } 
} 

Le premier appel à await sera exécuté, mais la deuxième déclaration console.log après il ne sera jamais apparaître. En outre, la boucle sera fermée immédiatement.

Comment puis-je exécuter une fonction comme mon importAttributeRecord() dans une boucle de façon synchrone, même si elle renvoie une promesse? Et pourquoi l'utilisation de "await" est-elle dangereuse pour les boucles?

+0

Voulez-vous dire par le second appel de journal celui qui sort: '" Après avoir persisté "'? Une exception est-elle levée? – k0pernikus

+4

A besoin de plus [mcve]. – melpomene

+4

La boucle n'est pas supprimée. Il est mis en attente et reprendra lorsque vous «attendez» la promesse. Les promesses sont asynchrones. Vous ne pouvez pas les traiter comme synchrones. –

Répondre

1

Ceci pourrait être décrit comme une "erreur de catégorie". Une boucle for est fondamentalement une idée de programmation synchrone, faisant chaque chose dans (typiquement) un tableau ou une autre entité indexée, l'un après l'autre, attendant à chaque fois.

La programmation asynchrone, implémentée par async, est une approche différente. La façon la plus parfaite de l'utiliser est simplement d'exprimer une relation entre la situation avant et après la situation, et de laisser le langage prendre soin de la synchronisation et éventuellement de l'exécution simultanée ou parallèle.

Pour cette situation, voici comment vous le faire:

async function importAttributeRecords(attributeValues, languageId, attributes, dataStorage, tx) { 
    return Promise.all(attributes.map(attr => { 
    console.log("Initiate persist", attr); 
    return importAttributeRecord(attributesValues, languageId, attr, dataStorage, tx).then(result => { 
     console.log("After persisting", attr, result); 
    }).catch(err => { 
     console.log("Error: ", attr, err); 
    })); 
    }); 
} 

Vous remarquerez que importAttributeRecords retourne maintenant un tableau de promesses, il est donc légitime async. Vous verrez également que ce code est légèrement plus court!

+0

1. Rien dans cet exemple n'attend les promesses de 'importAttributeRecord'. Avez-vous oublié 'Promise.all'? 2. Il n'y a rien de mal avec le code dans la question. Utiliser 'await' dans une boucle peut ne pas être conseillé car il fonctionnera en série, mais cela ne signifie pas que cela ne fonctionnera pas. Tout ce qui brise le code OP va aussi casser votre code. Une boucle 'for' est fondamentalement _serial_, mais elle n'est pas fondamentalement synchrone. – loganfsmyth

+0

@loganfsmyth 1. Qui a dit que l'appelant ne voulait pas utiliser 'Promise.race'? Avez-vous oublié cette possibilité? De plus, dites-vous que vous pensez que le retour du résultat d'un '.then' n'est pas idiomatique et compatible avec' async'? 2. Dites-vous que vous pensez que * serial * est idiomatique avec * asynchrone *? –

+1

"Qui a dit que l'appelant ne voulait pas utiliser Promise.race" Parce que la question originale a une boucle qui exécute très clairement chaque élément, les attendant tous. Mon point est 'return attributes.map (' renvoie un tableau de promesses, sans attendre que l'une d'elles se termine, où le code original ne revient très clairement de la fonction qu'une fois toutes les promesses faites. "for loop est fondamentalement une idée de programmation synchrone" ce qui n'est pas correct, mon point est que les boucles définissent le comportement d'ordonnancement.Le code peut être synchrone ou asynchrone indépendant de l'utilisation de la boucle – loganfsmyth