Bonjour à tous,

Depuis quelques temps je dev une appli avec l'aide de VueJS et une API REST sous Node.js.
Mais voilà un problème que je n'arrive pas à résoudre depuis quelques temps.

lors d'un appel de mon API afin de récupérer la liste d'articles, par exemple, ma recherche se fait dans plusieurs requete SQL ainsi qu'un convertisseur de rtf2html (me demandez pas pourquoi, j'utilise la base de donnée d'un logiciel vraiment très... :'( )

voici mon code

exports.findByID = async function(req, res){
  var id = req.params.id;
  var vDevis = ''
  var vRows = ''

  // Récupère les infos du devis (l'entête)
  var SQLquery = "SELECT * FROM W_DP.PCHANT as ch";
  SQLquery += " LEFT JOIN W_DP.PCLIENT as cl ON cl.CLNCLI = ch.CHNCLI"
  SQLquery += " LEFT JOIN W_DP.PPARETACH as et ON et.Ec_etach = ch.CHETATCH"
  SQLquery += " WHERE ch.CHCPRO = '" + id + "'"

  await sequelize.query(SQLquery).spread(function(rows, metadata) {
    var data = '"devis": ';

    for (var i = 0; i <= rows.length - 1; i++) {
      data += `
      { 
        "id": "`+rows[i].CHCPRO+`",
        .............bla bla bla........
      },`;
    }
    vDevis = data
  })

  // Récupére les lignes du devis
  var SQLquery  = "SELECT * FROM W_DP.PPROPOS as pr";
      SQLquery += " LEFT JOIN W_DP.PPRODV as dv ON dv.PR_RANG = pr.PRNRAN AND dv.PR_DEVIS = pr.PRCDEV"
      SQLquery += " WHERE PRCDEV = '" + id + "' AND PRENRE != 3 ORDER BY PRNRAN ASC"

  await sequelize.query(SQLquery).spread(function(rows, metadata) {
    var type = ''

    // Init la variable de retour
    var data = '"rows" : [';

    for (var i = 0; i <= rows.length - 1; i++) {

      // Stock le type de ligne dans la var {type} afin de pouvoir l'utiliser plus facilement plus bas.
      if(rows[i].PRENRE === '0'){
        type = 'title'
      }else if(rows[i].PRENRE === '1'){
        type = 'product'
      }

      let rRtf = null
      // Le texte en RTF est contenu dans rows[i].PR_TXT 
      rtfToHTML.fromString(rows[i].PR_TXT, (err, html) => {
        this.rRtf = html
      })

      data += `
          {
            "type": "`+type+`",
            "rang": `+rows[i].PRNRAN+`,
            "description": `+JSON.stringify(rows[i].PRTEXT)+`,
            "description_long": `+JSON.stringify(rRtf)+`,
            "qte": `+rows[i].PRQTEA+`,
            "tva": `+rows[i].PRTVA+`,
            "pu_ht": `+rows[i].PRPXOC+`,
            "remise": `+rows[i].PRREM+`,
            "total_ht": `+rows[i].PRHTX+`
        `;

      if (i === rows.length - 1){
        data += '}';
      }else{
        data += '},';
      }
    }
    data += ']';
    vRows = data
  });

  var data = '{"results": {' + vDevis + vRows + '}}';

  res.writeHead(200, {'Content-Type': 'application/json'});
  res.end(data);
};

Et là problème, impossible de passer rtfToHTML en await, du coup je ne récupère jamais le texte converti en html.
Et là je me pose la question, ma gestion de async est-elle correct ?

Je ne pense pas que ma façon de faire soit la meilleur, je suis un autodidacte et je fais sûrement beaucoup d'erreur, d'où ma demande d'aide :)

9 réponses


betaWeb
Réponse acceptée

Si tu as peur du "callback-hell", ce qui est comprehensible, utilise la lib async
Sinon, tu as l'air de ne pas être familier des callbacks toi ^^
Utilise async, tu déclares la variable qui recevra le résultat dans le scope global de ta méthod, tu fais chaque action (query SQL, conversion RTF->HTML etc) dans des tasks, puis tu retourne ton résultat dans le callback tu async.series

let result = []
let tasks = []
tasks.push(function (callback) { /* ... task 1 */ })
tasks.push(function (callback) { /* ... task 2 */ })
tasks.push(function (callback) { /* ... task 3 */ })
tasks.push(function (callback) { /* ... task N */ })
async.series(tasks, function (err) {
    if (err) // .. catch err
    // Tu retourne tes résultas ici
})

Salut,

Tu utilises async, mais tu passes quand même dans ton callback, c'est normal que tu ne récupères rien. Tu dois imbriquer tes callbacks et rendre ton HTML à la fin seulement. Je te conseille donc de refactorer ton code en fonction.
Et pour utiliser async await, il faut que la fonction / méthode renvoie une promise, est-ce le cas ici ?

Jielde
Auteur

Bonjour betaWeb,

SI je comprends bien, je dois mettre mon 2ème sequelize dans le premier ? (si c'est le cas j'ai un peu peur que mon code ne ressemble plus a rien si j'ai plusieurs imbrication....)

Je sais pas si j'utilise bien les promises, exemple avec le rtf2html (https://www.npmjs.com/package/@iarna/rtf-to-html), il me rend la variable html contenant mon rtf en html. Mais pour le retourner dans la fonction parent (donc la requete sequelize) je suis obligé de faire un

this.rRtf  = html

Fais-je bien les chose ?

Jielde
Auteur

Effectivement, je ne connais pas les callbacks, mais j'ai pas peur d'apprendre ;)

Je test ta fonction ce soir en rentrant et reviens vers toi après.
Merci pour ton aide.

Bonjour.
Grafikart a réalisé un tutoriel qui pourrait t'être utile pour mieux comprendre : Tutoriel vidéo Javascript » Promise, Async & Await.

Jielde
Auteur

Salut,

Désolé pour le retard dans ma réponse,
Alors j'ai un peu potassé les callback et j'ai suivi ton conseile betaweb.

je place toutes mes requêtes dans tasks.push(), je retourne le résultat avec des callback(null, data) et j'éxécute :

async.series(tasks, function (err, results) {
    if (err) { console.error(err) }
    // Tu retourne tes résultas ici
    //console.log(results)
    var data = '{"results": {' + results + '}}';

    res.writeHead(200, {'Content-Type': 'application/json; charset=utf-8'});
    res.end(data);
  })

Ceci m'a permis d'avoir un code beaucoup plus clair, je peu créer des task2.push() dans mes task.push ce qui est sympa.

Merci pour votre aide !!!

Salut,

Si tu veux pouvoir récupérer tes variables dans tes différents callbacks des tasks, tu dois utiliser async.waterfall() ;)
Mais sinon pas de quoi :)

Salut,

Si tu veux pouvoir récupérer tes variables dans tes différents callbacks des tasks, tu dois utiliser async.waterfall() ;)
Mais sinon pas de quoi :)

Jielde
Auteur

Salut,

Et encore une nouvelle fonction :) je ne vais plus domir ^^