回调首先运行? - learnyounode杂耍

时间:2015-11-03 20:44:36

标签: javascript node.js

有人可以帮助我理解为什么我的解决方案不起作用吗?似乎回调函数在juggle函数完成之前运行。

如果我删除评论,我的代码工作正常。只是我不明白为什么在juggle函数完成后不会调用日志函数。这就是回调应该如何正常工作?

提前致谢:)

var http = require('http')
links = process.argv.slice(2)
var contents = []
//var cbacks = 0

function juggle(callback) {
    links.forEach(function(link, i, links) {
        http.get(link, function(response) {
            response.setEncoding("utf8")
            var str = ""
            response.on("data", function(data) {
                str = str.concat(data)
            })
            response.on("end", function(){
                contents[i] = str
                //cbacks++
                //if(cbacks === 3) {
                //  callback()
                //}
            })
        })
    })
    callback()
}

function log() {
    contents.forEach(function(content, i, contents) {
        console.log(contents[i])
    })
}

juggle(log)

3 个答案:

答案 0 :(得分:1)

http.get是异步的。对您调用forEach的链接执行http.get,该链接注册要处理的连接。它实际上并没有完成连接/请求。

如果您需要在所有forEach函数完成后执行回调,则可以使用async之类的库来完成它。

async支持forEach方法。使用asyncforEach的第一个参数将采用额外的callback函数,应该调用该函数来表示项目处理已完成。您可以将该回调放入response.on('end')回调中。当所有这些回调被调用或发生错误时async.forEach将执行您作为第3个参数提供的onComplete回调,从而实现您的目标。

答案 1 :(得分:0)

您没有等待http响应并立即调用回调函数。此时代码contents数组为空。

答案 2 :(得分:0)

所以你有全局范围,这是我用来实际处理请求的方法。

当每个链接都注册到EventEmitter时,您可以将其存储在地图中。

var link_map = {};
var request_counter = 0;

links.forEach( function (link, index) {
    link_map[link] = '';
...

然后在您的请求中,您可以附加来自特定请求的数据

 response.on('data', function (chunk) {
    link_map[link] += chunk.toString();
...

最后在每一端,检查所有请求是否已完成

response.on('end', function () {
    request_counter += 1;
    if ( links.length === request_counter ) {
        // do your logging stuff here and you have all
        // the data that you need inside link_map
...

link中声明的匿名函数内的forEach变量存储在该闭包中。因此,每次发出'data'事件时,link变量将引用已注册到回调的特定链接的请求。这就是为什么我选择使用地图数据结构并将特定数据映射到我们用作关键字的每个链接。

如果你不熟悉它们,EventEmitters和回调会变得很难听。继续练习,最终会变得更容易。

使用数组并不是不正确或任何东西,我只是喜欢使用带键的对象=>我可以的价值对。

在您的计算机上

运行此代码以查看其运行情况。

const http = require('http');

var links = [
        'http://www.google.com',
        'http://www.example.com',
        'http://www.yahoo.com'
];
var link_map = {};
var request_counter = 0;

links.forEach( function (link, index) {
    link_map[link] = '';

    http.get(link, function(response) {
        response.on('data', function (chunk) {
            link_map[link] += chunk.toString();
        });

        response.on('end', function () {
            request_counter += 1;
            if ( links.length === request_counter ) {
                links.forEach( function(link) {
                    require('fs').writeFileSync(link.split('//')[1],link_map[link]);
                });
            }
        });
    });
});

您可以看到父目录中链接的文件输出。