2017-03-13 6 views
0

Ich habe ein Problem mit async Wasserfall, wo ich finde, dass nach dem Aufruf des zweiten Callback (cbNumPages) der erste Parameter "Seiten" ist der eigentliche Rückruf für die nächste Funktion, anstelle des letzten Parameters "cbGetFiles" was es sein sollte (soweit ich den asynchronen Wasserfall kenne sagt, dass letzter Parameter immer der Callback sein soll, ist das in diesem Fall offenbar nicht der Fall).NodeJs async Wasserfall (Callback-Methode ist keine Funktion)

Der Code ist der folgende:

async.waterfall 
      ([ 
       function(cbNumPages) 
       { 
        request({ 
         url: 'any-url', 
         qs: {}, 
         method: 'GET', 
         headers: { 
          'Authorization' : 'any-auth' 
         } 
        }, (err, response, body) => { 
         if (!err && response.statusCode == 200) 
         { 
          var $ = cheerio.load(body); 
          var pagesList = $('ol.aui-nav').children(); 
          if(pagesList.length<1) 
          { 
           var numPages = 1; 
          } else { 
           var numPages = pagesList.length-2; 
          } 
          console.log(numPages); 
          var pages = new Array(numPages), 
           total = numPages*20, 
           iterator = 0; 

          async.eachSeries(pages, function(page, cb) 
          { 
           if(page>1) 
           { 
            pages[iterator] = iterator; 
           }else { 
            pages[iterator] = iterator*20; 
           } 
           iterator++; 
           cb(); 
          }, function(err){ 
           if(err) cbNumPages(err); 
           cbNumPages(null, pages); 
          }); 
         } else { 
          cbNumPages(err); 
         } 
        }) 
       }, 

       function(pages, cbGetFiles) 
       { 
        var files = []; 
        var limitDate = moment().tz('Europe/Madrid').subtract(330,'days').format(); 

        async.eachSeries(pages, function(page, cb) 
        { 
         request({ 
          url: 'any-url'+page, 
          qs: {}, 
          method: 'GET', 
          headers: { 
           'Authorization' : 'any-auth' 
          } 
         }, (err, response, body) => { 
          if(!err && response.statusCode == 200) 
          { 
           var $ = cheerio.load(body); 
           var rows = $('tr[id^=\'attachment-\']'); 
           async.eachLimit(rows, 1, function(row, cb) 
           { 
            var id = row.attribs['id']; 
            var file = row.attribs['data-attachment-filename']; 
            var author = $(row).children('.creator').text().trim(); 
            var created = $(row).children('.created-date').text().trim(); 
             created = moment.tz(created, 'MMM D, YYYY', 'Europe/Madrid').format(); 
            var urlFile = 'simple-file' + $(row).children('.filename-column').children('.filename').attr('href'); 
            var extension = row.attribs['data-attachment-filename'].split('.'); 
             extension = extension[extension.length-1]; 
            if(created<limitDate && validExtensions.indexOf(extension)>-1) 
            { 
             var f = '{ "id": "' + id + '",'; 
              f += ' "file": "' + file + '",'; 
              f += ' "url": "' + urlFile + '",'; 
              f += ' "author": "' + author + '",'; 
              f += ' "modified": "' + created + '" }'; 
             files.push(JSON.parse(f)); 
            } 
            cb(); 
           }, (err) => { 
            if(err) cbGetFiles(err); 
           }); 
           cb(); 
          } else { 
           cb(err); 
          } 
         }); 
        }, function(err){ 
         if(err){ 
          cbGetFiles(err); 
         } else { 
          cbGetFiles(null, files); 
         } 
        }); 
       }, 

       function(files, cbGetAutors) 
       { 
        var filesFinal = {}; 
        for(var f in files) 
        { 
         if(!filesFinal[files[f].author]) 
         { 
          var ff = {}; 
          for(var i in files) 
          { 
           if(files[i].author === files[f].author) 
           { 
            ff[files[i].file] = files[i].url; 
           } 
          } 
          filesFinal[files[f].author] = ff; 
         } 
        } 
        cbGetAutors(null, JSON.parse(JSON.stringify(filesFinal))); 
       }, 

       function(filesFinal, cbSendEmail) 
       { 
        var authors = Object.keys(filesFinal); 
        async.eachSeries(authors, function(author, cb) 
        { 
         var name = author.split(' '); 

         var email = '[email protected]'; 
         var msg = '<p>Hi ' + author + ',</p><p>how is it going:</p><p>'; 
         for(var a in Object.keys(filesFinal[author])) 
         { 
          msg += '<p style="margin-left:20px"> '+ICON_DOC+' <a href="'; 
          msg += filesFinal[author][Object.keys(filesFinal[author])[a]]+'">'+Object.keys(filesFinal[author])[a]+'</a></p>'; 
         } 
         msg += '</p></p><p><b>NOTE: This is a no-reply address.</b></p><p>Have a nice day! '+ICON_MONKEY+'</p>'; 

         var message = { 
          text: msg, 
          from: '[email protected]', 
          to:  email, 
          bcc:  '', 
          subject: 'Sample subject', 
          attachment: [{data: msg, alternative: true}] 
         }; 

         serverEmail.send(message, function(err, message) 
         { 
          if(err) 
          { 
           cb(err); 
          } else { 
           console.log(message); 
           cb(); 
          } 
         }); 

        }, function(err){ 
         if(err) cbSendEmail(err); 
         cbSendEmail(); 
        }); 
       } 

      ], (err) => { 
       if(err) console.log(err); 
      }); 

Ich möchte wissen, ob es einen Weg gibt, dieses Problem zu kontrollieren oder zumindest, wenn es eine andere Optionen für die sind, was ich tun möchte.

Danke.

+1

In Ihrem Code 'if (err) cbNumPages (err);' 'verwenden return' . Überprüfen Sie "Common Pitfalls" Abschnitt in http://caolan.github.io/async/ – Sangharsh

+1

@Sangharsh würde nicht dazu führen, dass ein "Rückruf wurde bereits aufgerufen" Fehler, wenn das das Problem wäre? @avilac Ist es möglich, dass der Rückgabecode von 'any-url' nicht 200 ist, was zu dem Aufruf' cbNumPages (err) 'führt, wobei' err 'gleich 'null' ist? Dies führt dazu, dass "async" denkt, dass kein Fehler und kein Rückgabewert bereitgestellt wird, was dazu führt, dass der Rückruf als erstes Argument an die zweite Funktion von 'Wasserfall' übergeben wird. – YSK

+0

@YSK Ihre Vermutung ist sehr wahrscheinlich richtig. Mein Kommentar bezieht sich auf die Programmierpraxis. – Sangharsh

Antwort

2

Eine bessere (saubere) Möglichkeit, asynchronen Wasserfall zu verwenden.

Stellen Sie sicher, dass Sie vor jeder Callback-Funktion return verwenden. Ich habe sie im Code hinzugefügt.

Wenn Sie jede Serie verschachteln, ist es besser, der Callback-Funktion einen anderen Namen zu geben als die übergeordnete Callback-Funktion.

Ich habe 'cb' von Kindern async.series zu 'inner_cb' geändert

Aktualisiert Code:

async.waterfall 
([ 
    funcOne, 
    funcTwo, 
    funcThree, 
    funcFour  
], (err) => { 
    if(err) console.log(err); 
}); 

funciton funcOne(cbNumPages) { 
    request({ 
     url: 'any-url', 
     qs: {}, 
     method: 'GET', 
     headers: { 
      'Authorization' : 'any-auth' 
     } 
    }, (err, response, body) => { 
     if (!err && response.statusCode == 200) 
     { 
      var $ = cheerio.load(body); 
      var pagesList = $('ol.aui-nav').children(); 
      if(pagesList.length<1) 
      { 
       var numPages = 1; 
      } else { 
       var numPages = pagesList.length-2; 
      } 
      console.log(numPages); 
      var pages = new Array(numPages), 
       total = numPages*20, 
       iterator = 0; 

      async.eachSeries(pages, function(page, cb) 
      { 
       if(page>1) 
       { 
        pages[iterator] = iterator; 
       }else { 
        pages[iterator] = iterator*20; 
       } 
       iterator++; 
       return cb(); 
      }, function(err){ 
       if(err) return cbNumPages(err); 
       return cbNumPages(null, pages); 
      }); 
     } else { 
      return cbNumPages(err); 
     } 
    }) 
} 

function funcTwo(pages, cbGetFiles) { 
    var files = []; 
    var limitDate = moment().tz('Europe/Madrid').subtract(330,'days').format(); 

    async.eachSeries(pages, function(page, cb) 
    { 
     request({ 
      url: 'any-url'+page, 
      qs: {}, 
      method: 'GET', 
      headers: { 
       'Authorization' : 'any-auth' 
      } 
     }, (err, response, body) => { 
      if(!err && response.statusCode == 200) 
      { 
       var $ = cheerio.load(body); 
       var rows = $('tr[id^=\'attachment-\']'); 
       async.eachLimit(rows, 1, function(row, inner_cb) 
       { 
        var id = row.attribs['id']; 
        var file = row.attribs['data-attachment-filename']; 
        var author = $(row).children('.creator').text().trim(); 
        var created = $(row).children('.created-date').text().trim(); 
         created = moment.tz(created, 'MMM D, YYYY', 'Europe/Madrid').format(); 
        var urlFile = 'simple-file' + $(row).children('.filename-column').children('.filename').attr('href'); 
        var extension = row.attribs['data-attachment-filename'].split('.'); 
         extension = extension[extension.length-1]; 
        if(created<limitDate && validExtensions.indexOf(extension)>-1) 
        { 
         var f = '{ "id": "' + id + '",'; 
          f += ' "file": "' + file + '",'; 
          f += ' "url": "' + urlFile + '",'; 
          f += ' "author": "' + author + '",'; 
          f += ' "modified": "' + created + '" }'; 
         files.push(JSON.parse(f)); 
        } 
        return inner_cb(); 
       }, (err) => { 
        if(err) return cbGetFiles(err); 
       }); 
       return cb(); 
      } else { 
       return cb(err); 
      } 
     }); 
    }, function(err){ 
     if(err){ 
      return cbGetFiles(err); 
     } else { 
      return cbGetFiles(null, files); 
     } 
    }); 
} 

function funcThree(files, cbGetAutors) { 
    var filesFinal = {}; 
    for(var f in files) 
    { 
     if(!filesFinal[files[f].author]) 
     { 
      var ff = {}; 
      for(var i in files) 
      { 
       if(files[i].author === files[f].author) 
       { 
        ff[files[i].file] = files[i].url; 
       } 
      } 
      filesFinal[files[f].author] = ff; 
     } 
    } 
    return cbGetAutors(null, JSON.parse(JSON.stringify(filesFinal))); 
} 

function funcFour(filesFinal, cbSendEmail) { 
    var authors = Object.keys(filesFinal); 
    async.eachSeries(authors, function(author, cb) 
    { 
     var name = author.split(' '); 

     var email = '[email protected]'; 
     var msg = '<p>Hi ' + author + ',</p><p>how is it going:</p><p>'; 
     for(var a in Object.keys(filesFinal[author])) 
     { 
      msg += '<p style="margin-left:20px"> '+ICON_DOC+' <a href="'; 
      msg += filesFinal[author][Object.keys(filesFinal[author])[a]]+'">'+Object.keys(filesFinal[author])[a]+'</a></p>'; 
     } 
     msg += '</p></p><p><b>NOTE: This is a no-reply address.</b></p><p>Have a nice day! '+ICON_MONKEY+'</p>'; 

     var message = { 
      text: msg, 
      from: '[email protected]', 
      to:  email, 
      bcc:  '', 
      subject: 'Sample subject', 
      attachment: [{data: msg, alternative: true}] 
     }; 

     serverEmail.send(message, function(err, message) 
     { 
      if(err) 
      { 
       return cb(err); 
      } else { 
       console.log(message); 
       return cb(); 
      } 
     }); 

    }, function(err){ 
     if(err) return cbSendEmail(err); 
     return cbSendEmail(); 
    }); 
} 
+1

Danke für deine Zeit, ein guter Rat ist immer hilfreich! :) – avilac

+0

Immer glücklich zu helfen :) –

0

Wie @YSK in einem Kommentar sagte, erhielt ich eine 401 aus dem response.statusCode und daher wird es auf die cbSendEmail (err) fehlgeleitet mit err beying null. Die nächste Methode im ersten Parameter des Wasserfalls erstellt den Rückruf anstelle des zweiten.

Verwandte Themen