【问题标题】:Node.js + Cheerio : Request inside a loopNode.js + Cheerio:循环内的请求
【发布时间】:2016-02-04 01:40:36
【问题描述】:

我正在使用 Cheerio、request 和 Node.js。

当我运行下面的脚本时,它以错误的顺序输出名称。我相信它是由它的异步性质引起的,我怎样才能让它以“正确”的顺序工作?我是否需要使用同步包,或者有没有办法以某种方式对其进行更改,使其能够以同步方式工作?

app.get('/returned', function (req, res) {
    for (var y = 0; y < 10; y++) {
        var url = "http://example.com" + y + "/person.html";
        request(url, function (err, resp, body) {
            $ = cheerio.load(body);
            var links = $('#container');
            var name = links.find('span[itemprop="name"]').html(); // name
            if (name == null) {
                console.log("returned null");
            } else {
                console.log(name);
            }

        });
    }
});

【问题讨论】:

  • 视情况而定。您想并行还是串行发送请求。假设您请求的服务器一次可以处理超过 1 个请求,串联会比并联慢得多。可以并行处理它,同时仍然按照您想要的顺序获得结果。
  • 并行。我认为 async 会完成这项工作(由@dm03514 回答),我会调查一下。
  • 请注意,他的答案是串联的,而不是平行的。但是 async 确实有一个并行选项,您只需要以某种方式以您想要的顺序存储结果,而不管它们是否会被乱序调用。
  • 一开始为什么要用app.get?我正在尝试从这个示例中做一些非常相似的工作,但我真的被卡住了!已阅读请求 github 文档,但没有帮助。

标签: node.js cheerio


【解决方案1】:

Promise 让这件事变得相对容易:

app.get('/returned', function (req, res) {
    let urls = [];
    for (let y = 0; y < 10; y++) {
        urls.push('http://example.com' + y + '/person.html');
    }
    Promise.all(urls.map(function (url) {
        return new Promise(resolve, reject) {
            request(url, function (err, resp, body) {
                if (err) {return reject(err);}
                let $ = cheerio.load(body);
                let links = $('#container');
                let name = links.find('span[itemprop="name"]').html(); // name
                resolve({name: name, links: links, url: url});
            });
        });
    }).then(function (result) {
        result.forEach(function (obj) {
            if (obj.name == null) {
                console.log(obj.url, "returned null");
            } else {
                console.log(obj.url, obj.name);
            }
        });
    }).catch(function (err) {
        console.log(err);
    });
});

我首先创建了一个要获取的 url 数组,然后我将其映射到一个 Promise 数组。当每个请求都完成后,我用名称、url 和链接解决了 promise。当所有的承诺都完成后,我然后循环遍历将按原始顺序排列的结果。这并行运行。

【讨论】:

  • "app.get('/returned',..." 是做什么的?这是一个特定于这个例子的目录吗?我正在尝试重新创建类似的东西。
【解决方案2】:

不,您不应该使用同步包。 IMO 最干净的方法是使用成熟的 3rd 方库。

我推荐异步。

async.series 方法将按照给定的顺序执行所有请求函数,然后允许您注册回调以在所有请求完成或发生错误时触发。

https://github.com/caolan/async#seriestasks-callback

【讨论】:

    猜你喜欢
    • 2014-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-09
    • 2016-12-17
    • 2020-11-02
    相关资源
    最近更新 更多