web-dev-qa-db-fra.com

Javascript, comment attendre plusieurs promesses

Ce que je veux accomplir:

  • recueillir les identifiants d’artistes
    • soit les trouver dans la db
    • en les créant
  • créer un événement dans la base de données, obtenir l'event_id
  • attendre que les deux soient terminés, artistes et événements rassemblés
  • boucle maintenant sur l'artiste, combinaisons d'événements

Ce que j'ai:

Je travaille avec Node et mysql. Pour insérer les relations, je dois attendre que les artistes insèrent ou créent. J'essaie d'accomplir avec le code suivant:

let promises = [];

if (artists.length != 0) {
    for (key in artists) {
        promises.Push( find_artist_id_or_create_new_artist(artists[key]) )
    }
}

await Promise.all(promises);

Renvoyer un identifiant:

async function find_artist_id_or_create_new_artist(artist_name) {
    return await find_artist_return_id(artist_name, create_artist_return_id)
} 

Trouver un artiste:

async function find_artist_return_id(artist_name, callback) {
    var sql = "SELECT * FROM `artists` WHERE `name` LIKE "+con.escape(artist_name)+" LIMIT 1;"

    con.query(sql, (err,row) => {
      if(err) throw err;

      if (row.length == 0) {
        return callback(artist_name)
      } else {
        return row[0].id
      }
    });
}

Créer un artiste

async function create_artist_return_id(artist_name) {
    var sql = "INSERT INTO `artists` (`id`, `name`, `meta_1`, `meta_2`) VALUES (NULL, "+con.escape(artist_name)+", NULL, NULL)";

    con.query(sql, (err, result) => {
      if(err) throw err;

      return result.insertId
    });
}

Je comprends que je ne peux pas revenir dans une fonction con.query, mais je ne sais pas comment configurer correctement le code pour que cela soit fait. Un lien vers ou une aide pour rechercher une réponse est apprécié.

8
bart great

Votre SQL functions fondamental doit être converti en promises pour être awaited.

Voir Async Function , Promise et Array.prototype.map() pour plus d'informations.

// Artist Ids.
const artistIds = await Promise.all(artists.map(async (artist) => await findArtist(artist) || await createArtist(artist)))

// Find Artist.
const findArtist = artist => new Promise((resolve, reject) => con.query(`SELECT * FROM \`artists\` WHERE \`name\` LIKE ${con.escape(artist)} LIMIT 1;`, async (error, row) => {
  if(error) return reject(error)
  if (!row.length) return resolve(await createArtist(artist)) 
  return resolve(row[0].id)
}))

// Create Artist.
const createArtist = artist => new Promise((resolve, reject) => con.query(`INSERT INTO \`artists\` (\`id\`, \`name\`, \`meta_1\`, \`meta_2\`) VALUES (NULL, ${con.escape(artist)}, NULL, NULL)`, (error, result) => {
  if (error) return reject(error)
  return resolve(result.insertId)
}))
3
Arman Charan

Vous devez juste envelopper les rappels mysql dans des promesses:

 function find_artist_return_id(artist_name) {
  return new Promise((resolve, reject) => {
     var sql = "SELECT * FROM `artists` WHERE `name` LIKE "+con.escape(artist_name)+" LIMIT 1;"

      con.query(sql, (err,row) => {
         if(err) return reject(err);

         if (row.length == 0) {
           return resolve(artist_name);

           return resolve(row[0].id);      
      });
   });
}

Et au fait, c'est très moche:

 if (artists.length != 0) {
   for (key in artists) {

Il suffit de faire:

  for(const artist of artists)
    promises.Push(someApiCall(artist));

ou:

  const promises = artists.map(someApiCall);
0
Jonas Wilms

La méthode la plus simple consiste à utiliser les commandes déjà existantesORMlike sequalizejs ou etc, car elles vous renvoient des promesses et au lieu de rechercher et créer dans une requête Raw séparée dans le pilote MySQL natif. Vous pouvez simplement utiliser les API comme trouver ou créer quelque chose.

je vous explique comment async fonctionne dans votre exemple, j'ai pris un morceau de code de votre exemple.

    async function createArtist(artist_name) {
    var sql = "INSERT INTO `artists` (`id`, `name`, `meta_1`, `meta_2`) VALUES (NULL, "+con.escape(artist_name)+", NULL, NULL)";

    con.query(sql, (err, result) => {
        if(err) throw err;

        return result.insertId
    });
}

const artistId = (async () => {
    await createArtist('maxi');
})();

regardez dans createArtist function c'est exactement ce que vous avez. Trois choses que vous devez noter ici,

  1. vous déclarez une fonction asynchrone pour qu'il retourne promesse par défaut.
  2. il peut simplement renvoyer n'importe quoi comme une fonction normale, s'il s'agit d'une fonction synchrone, évitez d'utiliser asynchrone.
  3. Comme vous l'avez dit, vous ne pouvez rien retourner du rappel. comme il est asynchrone, vous devez retourner la promesse.

de sorte que le code peut être changé pour

    async function createArtist(artist_name) {
    return new Promise((resolve,reject)=>{
        var sql = "INSERT INTO `artists` (`id`, `name`, `meta_1`, `meta_2`) VALUES (NULL, "+con.escape(artist_name)+", NULL, NULL)";

        con.query(sql, (err, result) => {
            if(err) reject(err);
            resolve(result.insertId)
        });
    });
}

const artistId = (async () => {
    await createArtist('maxi');
})();

Les choses ont changé ici, ajouté un wrapper natif de promesse et le retourne avant qu'il ne devienne asynchrone. appelé résoudre pour réussir. Et rejeter pour le faire échouer.

N'oubliez pas d'ajouter try ... catch blog for wait's pour gérer les erreurs.

0
Vignesh