【问题标题】:node.js looping through GETs with promisenode.js 循环通过带有承诺的 GET
【发布时间】:2016-06-10 14:18:01
【问题描述】:

我是 Promise 的新手,我确信那里有一个答案/模式,但我只是找不到一个对我来说足够明显的答案/模式是正确的。我正在使用 node.js v4.2.4 和 https://www.promisejs.org/

我认为这应该很容易...我需要按特定顺序执行多个异步块,其中一个中间块将循环通过一组 HTTP GET。

//New Promise = asyncblock1 - FTP List,解析返回的list数组 //.then(asynchblock2(list)) - 遍历列表数组和 HTTP GET 需要的文件 //.then(asynchblock3(list)) - 更新本地日志

我尝试创建一个新的 Promise,解决它,将列表传递给 .then,执行 GET 循环,然后更新文件。我尝试在 asynchblock2 中使用嵌套的 promise.all,但由于这些事件的时间安排,它实际上以相反的顺序进行,3、2 和 1。感谢您的帮助。

编辑:好的,这是我正在使用的有效模式,我现在只需要在中间有一个 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);
  });
});

编辑这是几乎可以工作的代码!

 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;
        // });
      });
    });
})();

-->> 这里发生了什么: 所以我添加了几乎可以工作的代码。发生的情况是,对于每个其他文件,都会发出一个额外的 Get 请求(我不知道它是如何被触发的),该请求失败并显示“无法建立数据连接”。

因此,对于我对这 6 个数组的迭代,最终有 9 个 Get 请求。请求元素 1(有效且预期),然后请求 2(有效且预期),然后再次请求 2(失败且意外/不知道为什么触发它)。然后是 3(工作和预期),然后是 4(工作和预期),然后是 4(失败和意外)等等

【问题讨论】:

  • 请向我们展示您尝试过的实际代码,并更详细地描述您想要完成的工作。
  • 在 OP 中,我添加了我为自己制作的模式示例。 settimeout 以相反的顺序运行而没有工作承诺的方式被触发。我的实际代码在我正在制作并试图重写的便便程序的旋风中。

标签: javascript node.js asynchronous ftp promise


【解决方案1】:

您需要的是Promise.all(),您的应用的示例代码:

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

【讨论】:

  • 所以这是可行的,但是我的最后一个问题是,以某种方式触发了一个额外的 GET 请求,该请求不起作用。所有文件都下载了,但我对如何触发额外的 GET 请求感到困惑。编辑 OP
【解决方案2】:

所以感谢您的帮助(以及没有有用方向的反对票!)

我实际上联系了一位优秀的 nodejs 程序员,他说我正在使用的 ftp 模块中似乎有一个错误,即使在尝试使用 blackbird .map 时,快速连续的请求以某种方式开始了错误。我最终使用了 promise-ftp、blackbird 和 promiseTaksQueue - 关键是我需要 interval。没有它,ftp 最终会导致 ftp 模块中出现奇怪的不合逻辑错误。

【讨论】:

    【解决方案3】:

    您需要异步库。在需要在循环中使用异步操作的情况下使用 async.eachSeries,然后在所有这些都完成后执行一个函数。根据您想要的流程,有很多变化,但这个库可以做到。

    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
    });
    

    【讨论】:

      猜你喜欢
      • 2019-06-17
      • 2013-06-17
      • 1970-01-01
      • 2017-07-18
      • 1970-01-01
      • 2020-08-16
      • 1970-01-01
      相关资源
      最近更新 更多