简体   繁体   English

node.js 使用 promise 循环遍历 GET

[英]node.js looping through GETs with promise

I'm new to promises and I'm sure there's an answer/pattern out there but I just couldn't find one that was obvious enough to me to be the right one.我是 Promise 的新手,我确信那里有一个答案/模式,但我只是找不到一个对我来说足够明显的正确答案。 I'm using node.js v4.2.4 and https://www.promisejs.org/我正在使用 node.js v4.2.4 和https://www.promisejs.org/

This should be pretty easy I think...I need to do multiple blocks of async in a specific order, and one of the middle blocks will be looping through an array of HTTP GETs.我认为这应该很容易...我需要按特定顺序执行多个异步块,其中一个中间块将循环遍历一组 HTTP GET。

//New Promise = asyncblock1 - FTP List, resolve the returned list array //.then(asynchblock2(list)) - loop through list array and HTTP GET needed files //.then(asynchblock3(list)) - update local log //New Promise = asyncblock1 - FTP List,解析返回的列表数组 //.then(asynchblock2(list)) - 循环遍历列表数组和HTTP GET需要的文件 //.then(asynchblock3(list)) - 更新本地日志

I tried creating a new Promise, resolving it, passing the list to the .then, doing the GET loop, then the file update.我尝试创建一个新的 Promise,解决它,将列表传递给 .then,执行 GET 循环,然后更新文件。 I tried using a nested promise.all inside asynchblock2, but it's actually going in reverse order, 3, 2, and 1 due to the timing of those events.我尝试在 asynchblock2 中使用嵌套的 promise.all,但由于这些事件的时间安排,它实际上以相反的顺序进行,即 3、2 和 1。 Thanks for any help.谢谢你的帮助。

EDIT: Ok, this is the pattern that I'm using which works, I just need a GET loop in the middle one now.编辑:好的,这是我正在使用的模式,我现在只需要在中间一个 GET 循环。

var p = new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('2 sec');
    resolve(1);
  },
  2000);
}).then(() => {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log('1.5 sec');

// instead of this section, here I'd like to do something like:
// for(var i = 0; i < dynamicarray.length; i++){
//   globalvar[i] = ftpclient.getfile(dynamicarray[i])
// }
// after this loop is done, resolve

      resolve(1);
    },
    1500);
  });
}).then(() => {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log('1 sec');
      resolve(1);
    },
    1000);
  });
});

EDIT Here is the almost working code!编辑这是几乎可以工作的代码!

 var pORecAlert = (function(){

  var pa;
  var newans = [];
  var anstodownload = [];
  var anfound = false;//anfound in log file
  var nexttab;
  var lastchar;
  var po;
  var fnar = [];
  var antext = '';

//-->> This section works fine; it's just creating a JSON object from a local file
    try{
        console.log('trying');
        porfile = fs.readFileSync('an_record_files.json', 'utf8');
        if(porfile == null || porfile == ''){
            console.log('No data in log file - uploaded_files_data.json being initialized!');
            plogObj = [];
        }
        else{
            plogObj = JSON.parse(porfile);
        }
    }
    catch(jpfp){
        console.log('Error parsing log file for PO Receiving Alert: ' + jpfp);
        return endPORecAlertProgram();
    };
    if((typeof plogObj) === 'object'){
        console.log('an_record_files.json log file found and parsed for PO Receiving Alert!');
    }
    else{
        return mkError(ferror, 'pORecAlert');
    };
//finish creating JSON Object

    pa = new Client();
    pa.connect(ftpoptions);
    console.log('FTP Connection for FTP Check Acknowledgement begun...');
    pa.on('greeting', function(msg){
      console.log('FTP Received Greeting from Server for ftpCheckAcknowledgement: ' + msg);
    });
    pa.on('ready', function(){
      console.log('on ready');

      //START PROMISE LIST
      var listpromise = new Promise((reslp, rejlp) => {
            pa.list('/public_html/test/out', false, (cerr, clist) => {
              if(cerr){
                    return mkError(ferror, 'pORecAlert');
              }
              else{
                    console.log('Resolving clist');
                    reslp(clist);
              }
            });
      });
      listpromise.then((reclist) => {
          ftpplist:
          for(var pcl = 0; pcl < reclist.length; pcl++){
                console.log('reclist iteration: ' + pcl);
                console.log('checking name: ', reclist[pcl].name);
                if(reclist[pcl].name.substring(0, 2) !== 'AN'){
                  console.log('Not AN - skipping');
                  continue ftpplist;
                }
                else{//found an AN
                  for(var plc = 0; plc < plogObj.length; plc++){
                        if(reclist[pcl].name === plogObj[plc].anname){
                          //console.log('Found reclist[pcl].name in local log');
                          anfound = true;
                        };
                  };
                  if(anfound === false){
                        console.log('Found AN file to download: ', reclist[pcl].name);
                        anstodownload.push(reclist[pcl].name);
                  };
                };
          };
          console.log('anstodownload array:');
          console.dir(anstodownload);
          return anstodownload;
      }).then((fnar) => {
            //for simplicity/transparency, here is the array being overwritten
            fnar = new Array('AN_17650_37411.699.txt', 'AN_17650_37411.700', 'AN_17650_37411.701', 'AN_17650_37411.702.txt', 'AN_17650_37411.801', 'AN_17650_37411.802.txt');
        return Promise.all(fnar.map((gfname) => {
            var nsalertnames = [];
          console.log('Getting: ', gfname);
          debugger;
          pa.get(('/public_html/test/out/' + gfname), function(err, anstream){//THE PROBLEM IS THAT THIS GET GETS TRIGGERED AN EXTRA TIME FOR EVERY OTHER FILE!!!
                antext = '';
                console.log('Get begun for: ', gfname);
                debugger;
                if(err){
                  ferror.nsrest_trace = 'Error - could not download new AN file!';
                  ferror.details = err;
                  console.log('Error - could not download new AN file!');
                  console.log('************************* Exiting *************************')
                  logError(ferror, gfname);
                }
                else{
                  // anstream.on('data', (anchunk) => {
                  //   console.log('Receiving data for: ', gfname);
                  //   antext += anchunk;
                  // });
                  // anstream.on('end', () => {
                  //   console.log('GET end for: ', gfname);
                  //   //console.log('path to update - gfname ', gfname, '|| end text.');
                  //   fs.appendFileSync(path.resolve('test/from', gfname), antext);
                  //   console.log('Appended file');
                  //   return antext;
                  // });//end end
                };
          });//get end
        }));//end Promise.all and map
      }).then((res99) => {
        // pa.end();
        // return Promise(() => {
           console.log('end all. res99: ', res99);
        //   //res4(1);
        //   return 1;
        // });
      });
    });
})();

-->> What happens here: So I added the almost working code. -->> 这里发生了什么:所以我添加了几乎可以工作的代码。 What is happening is that for every other file, an additional Get request gets made (I don't know how it's being triggered), which fails with an "Unable to make data connection".发生的情况是,对于每个其他文件,都会发出一个额外的 Get 请求(我不知道它是如何触发的),该请求因“无法建立数据连接”而失败。

So for my iteration over this array of 6, there ends up being 9 Get requests.因此,对于我对这个 6 数组的迭代,最终有 9 个 Get 请求。 Element 1 gets requested (works and expected), then 2 (works and expected), then 2 again (fails and unexpected/don't know why it was triggered).元素 1 被请求(有效和预期),然后是 2(有效和预期),然后是 2(失败和意外/不知道它为什么被触发)。 Then 3 (works and expected), then 4 (works and expected), then 4 again (fails and unexpected) etc然后是 3(有效和预期),然后是 4(有效和预期),然后是 4(失败和意外)等等

what you need is Promise.all() , sample code for your app:您需要的是Promise.all() ,您的应用程序的示例代码:

...
}).then(() => {
  return Promise.all(arry.map(item => ftpclient.getFile(item)))
}).then((resultArray) => {
...

So thanks for the help (and the negative votes with no useful direction!)所以感谢您的帮助(以及没有有用方向的反对票!)

I actually reached out to a good nodejs programmer and he said that there seemed to be a bug in the ftp module I was using, and even when trying to use a blackbird .map, the quick succession of requests somehow kicked off an error.我实际上联系了一位优秀的 nodejs 程序员,他说我正在使用的 ftp 模块中似乎存在一个错误,即使在尝试使用 blackbird .map 时,快速连续的请求也会以某种方式引发错误。 I ended up using promise-ftp, blackbird, and promiseTaksQueue - the kicker was that I needed interval .我最终使用了 promise-ftp、blackbird 和 promiseTaksQueue - 关键是我需要interval Without it the ftp would end up causing a strange illogical error in the ftp module.没有它,ftp 最终会在 ftp 模块中导致一个奇怪的不合逻辑的错误。

You need the async library.您需要异步库。 Use the async.eachSeries in situations where you need to use asynchronous operations within a loop, then execute a function when all of those are complete.在需要在循环中使用异步操作的情况下使用 async.eachSeries,然后在所有这些操作完成后执行函数。 There are many variations depending on the flow you want but this library does it all.根据您想要的流程有很多变化,但这个库可以做到这一切。

https://github.com/caolan/async https://github.com/caolan/async

async.each(theArrayToLoop, function(item, callback) {
 // Perform async operation on item here.
  doSomethingAsync(item).then(function(){
     callback();
  })
}, function(err){
   //All your async calls are finished continue along here
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM