Javascript 如何在for循环中使用node.js中的Request函数并使其以正确的顺序返回输出?

Javascript 如何在for循环中使用node.js中的Request函数并使其以正确的顺序返回输出?,javascript,node.js,request,cheerio,Javascript,Node.js,Request,Cheerio,我一直在使用request遍历几个XML条目,并使用cheerio.js将每一篇文章、日期和url返回到控制台。主要的问题是每次输出都会以不同的顺序出现,因为请求是一个异步函数。一般来说,我对javascript缺乏经验,想知道如何检索一致的输出(我一直在阅读有关异步和承诺的文章,我只是不确定如何实现它们)。 这是我的密码: var count = 0; for(var j = 0; j < arrNames.length; j++){ request('http://dblp.org

我一直在使用request遍历几个XML条目,并使用cheerio.js将每一篇文章、日期和url返回到控制台。主要的问题是每次输出都会以不同的顺序出现,因为请求是一个异步函数。一般来说,我对javascript缺乏经验,想知道如何检索一致的输出(我一直在阅读有关异步和承诺的文章,我只是不确定如何实现它们)。 这是我的密码:

var count = 0;
for(var j = 0; j < arrNames.length; j++){
  request('http://dblp.org/search/publ/api?q=' + arrNames[j], function(error, response, html){
    if (!error && response.statusCode == 200){
      var $ = cheerio.load(html, {xmlMode: true});
      console.log($('query').text()+'\n');

      $('title').each(function(i, element){
        var title = $('title').eq(i).text();
        var year = Number($('year').eq(i).text());
        var url = $('ee').eq(i).text();

        if (year >= arrTenures[count]){
          console.log(title);
          console.log(year);
          console.log(url + '\n');
        }
      });

      count++;
    }
  });
}
var计数=0;
对于(var j=0;j=任期[计数]){
控制台日志(标题);
对数(年);
console.log(url+'\n');
}
});
计数++;
}
});
}

看起来您正试图捕获每个请求的迭代次数,因此请使用
forEach
并使用其第二个参数,该参数指示迭代索引:

arrNames.forEach((q, requestIndex) => {
  request('http://dblp.org/search/publ/api?q=' + q, (error, response, html) => {
    if (error || response.statusCode == 200) return;
    var $ = cheerio.load(html, {
      xmlMode: true
    });
    console.log($('query').text() + '\n');
    $('title').each(function(i, element) {
      var title = $('title').eq(i).text();
      var year = Number($('year').eq(i).text());
      var url = $('ee').eq(i).text();
      if (year >= arrTenures[requestIndex]) {
        console.log(title);
        console.log(year);
        console.log(url + '\n');
      }
    });
  });
});

作为一个旁注,一致的缩进确实提高了代码可读性——您可以考虑一个LITER。

在您的第一次尝试中,您可能已经尝试过:

if (year >= arrTenures[j]) {
但我注意到这不起作用。这是因为范围界定问题

您可以通过使用迭代器(如
forEach()
)或简单地将for循环更改为使用
let
)来解决问题:

for(let j = 0; j < arrNames.length; j++){

虽然您已经找到了解决方案,但我想我会向您展示如何使用ES6 Promissions(一种管理多个异步操作的更现代的方法)来实现这一点:

这有几个优点:

  • Promise.all()
    为您整理结果
  • rp()
    为您检查2xx状态
  • 这可以更容易地与其他异步操作链接/排序
  • 错误处理更简单,低级错误会自动传播到顶层
  • 这是抛出安全的(如果抛出异步错误,则捕获并传播它们)

  • 如果您使用promises,它将是这样的
    Promise.all(arrNames.map(name=>request(“http://dblp.org/search/publ/api?q=“+name”)。然后(arrayWithResult=>{/*在这里做你的事*/})
    非常感谢您的快速回复!您在我尝试捕获每个请求的迭代编号时说得非常正确,这正是解决问题的方法!而且我的缩进在现实生活中稍微好一点,这是我第一次在so上发布,所以我搞砸了格式。谢谢!我不知道您可以用Javascript中的数组,谢谢你的想法!然后你可以做
    item.name
    item.tenures
    :)哈,我只是在谷歌上搜索如何访问这些元素!谢谢这是一个非常有帮助的回答,如果所有的东西都按顺序退回,那将是非常好的。这使得承诺看起来不像我想象的那么困难,很难从无关的例子中收集。谢谢
    [
      { name: 'some name', tenures: 2 },
      { name: 'another', tenures: 5 }
    ]
    
    const rp = require('request-promise');
    
    Promise.all(arrNames.map(item => {
        return rp('http://dblp.org/search/publ/api?q=' + item).then(html => {
            const $ = cheerio.load(html, {xmlMode: true});
    
            return $('title').map(function(i, element){
                const title = $(element).text();
                const year = Number($('year').eq(i).text());
                const url = $('ee').eq(i).text();
                return {title, year, url};
            }).get();
        });
    })).then(results => {
        // results is an array of arrays, in order
        console.log(results);
    }).catch(err => {
        console.log(err);
    });