Node.js 使用节点返回异步web查询的结果

Node.js 使用节点返回异步web查询的结果,node.js,Node.js,虽然我在概念上理解了节点(和ajax)的异步行为,但我总是对我认为必须执行的例行任务感到困惑。考虑下面的伪ISH代码: let result = []; request("http://server", function(error, response) { const links = response.links; // an array of links links.forEach(function(link) { request(link, functio

虽然我在概念上理解了节点(和ajax)的异步行为,但我总是对我认为必须执行的例行任务感到困惑。考虑下面的伪ISH代码:

let result = [];
request("http://server", function(error, response) {
    const links = response.links; // an array of links
    links.forEach(function(link) {
         request(link, function(error, response) {
             result.push(response.gold);
         });
         // *****C*****
    });
    // *****B*****
});
// *****A*****

我的问题是,何时将结果返回到web以便返回完整的结果?在
A
B
上,结果可能还没有准备好,但我只能以某种流式方式返回
C
的结果,我不知道怎么做。处理这种事情的正确方法是什么(让我们假设,虽然我只显示了第一个
响应的一个下降级别,但我如何处理任何级别的下降)?此外,我还想知道一种不使用任何外部辅助程序库(如
async
)的方法。我不反对使用这样的东西,但我想了解在
nodejs中,由于它的异步性质,应该如何做一些事情。

您使用了函数push,它基本上是以后进先出的形式添加元素。而不是使用unshift函数。 如果你不明白的话
请参阅此链接。

您可以使用Promiss和nodejs v8中的
async
wait
对其进行存档

首先,您需要让请求函数返回承诺,而不是使用回调。因此,要么承诺它,要么使用返回承诺的库。 现在您可以像这样编写一个异步函数

var requestPromisified = require('request-promise');

async function getGoldData() {
    var response = await requestPromisified('http://example.com');
    var links = ['http://example.com']; //get links somehow from response
    var goldPromises = links.map(async function (link) {
        var response = await requestPromisified(link);
        var gold = 0; //get gold somehow from response
        return gold;
    });
    return Promise.all(goldPromises);
}
然后在其他异步上下文中使用该函数,例如在快速路由回调中。(额外建议:使用该模块,这样就不必使用
next(err);
该模块会自动将被拒绝的承诺传递给下一个中间件。)

或者在任何地方都可以这样称呼它:

getGoldData().then(function(goldData){
    console.log('goldData:', goldData);
}).catch(function(err){
    console.log('ERROR:', err);
});

让我们尝试解析两个youtube URL并处理它们。承诺会使代码更容易推理

const sonyPictures = 'https://www.youtube.com/playlist?list=PLYeOyMz9C9kYmnPHfw5-ItOxYBiMG4amq';
const fox = 'https://www.youtube.com/playlist?list=PLfPBohF1uFwoO5wBnYD67i0pbZ6GqrGEd';
const allURLs = [sonyPictures, fox];
现在我们有了一个数组,我们想在它上面循环。现在我们需要提出请求并保存承诺

const cheerio = require('cheerio');
const rp = require('request-promise');
const playlistArrayPromises = [];

下一步是等待所有这些承诺得到解决(或拒绝),我们可以执行我们想要的行动

Promise.all(playlistArrayPromises).then((result) => {
    console.log(result.length);
    console.log('here');
    return 0;
  });
现在,结果按照发出请求的顺序包含所有parsedURL响应

您可以将其扩展到任何级别。你所要做的就是等待所有的承诺通过承诺来解决。所有这些都在子级,一旦完成,你就可以继续

以下是可以在安装了节点和所需软件包的情况下运行的完整代码

const cheerio = require('cheerio');
const rp = require('request-promise');

const sonyPictures = 'https://www.youtube.com/playlist?list=PLYeOyMz9C9kYmnPHfw5-ItOxYBiMG4amq';
const fox = 'https://www.youtube.com/playlist?list=PLfPBohF1uFwoO5wBnYD67i0pbZ6GqrGEd';
const allURLs = [sonyPictures, fox];
const playlistArrayPromises = [];

const main = () => {
  allURLs.forEach((channelURL) => {
    const options = {
      uri: channelURL,
      transform: function (body) {
        return cheerio.load(body);
      },
    };
    playlistArrayPromises.push(rp(options));
  });
  Promise.all(playlistArrayPromises).then((result) => {
    console.log(result.length);
    return 0;
  });
};




main();

您可以将旧样式与回调一起使用。或者你可以使用promises(然后还可以使用
async
wait
关键字(而不是库)来编写代码,就像你在一个同步世界一样。(因此,你可以使用try-catch和returns。我想说,真的很好)你能给我提供一个示例代码片段吗?你打算使用最新版本的node 8.x吗?在6版本中,
async
await
不可用。。。。我可以写下我将如何做,但idk如果这是最好的方式…哈,好捕获!奇怪的是,我在笔记本电脑上使用了8.x,但在服务器上使用了6.x,我将在服务器上托管应用程序。因此,这加强了对一些真正基本的东西的需要。正如我所说的,这听起来像是一项常规的web任务,必须有一种基本的核心功能来完成。我会在内容块准备好后立即将其推入响应。我不确定推送与取消移动是否有关系。它们似乎与我所问的问题无关。这个答案令人困惑。我想说的一件事是,您最好使用完整的ES6+并提倡箭头语法而不是函数和const/let over var。
Promise.all(playlistArrayPromises).then((result) => {
    console.log(result.length);
    console.log('here');
    return 0;
  });
const cheerio = require('cheerio');
const rp = require('request-promise');

const sonyPictures = 'https://www.youtube.com/playlist?list=PLYeOyMz9C9kYmnPHfw5-ItOxYBiMG4amq';
const fox = 'https://www.youtube.com/playlist?list=PLfPBohF1uFwoO5wBnYD67i0pbZ6GqrGEd';
const allURLs = [sonyPictures, fox];
const playlistArrayPromises = [];

const main = () => {
  allURLs.forEach((channelURL) => {
    const options = {
      uri: channelURL,
      transform: function (body) {
        return cheerio.load(body);
      },
    };
    playlistArrayPromises.push(rp(options));
  });
  Promise.all(playlistArrayPromises).then((result) => {
    console.log(result.length);
    return 0;
  });
};




main();