以下代码两次输出端口号40001,然后错误退出:

Error: listen EADDRINUSE


我相信这是因为代码是异步的,并且在分配另一个端口之前不会等待foreach循环的整个迭代。

我应该使用哪个Node惯用法来解决这个问题?我想遍历数组,并在每次迭代的不同端口上建立phantomJS连接。

posts.forEach(function(element, index, posts){

        portscanner.findAPortNotInUse(40000, 60000, 'localhost', function(err, freeport) {
        if(err) {
            console.log(err);
        }
            console.log(freeport); //outputs 40001 twice then exits
            phantom.create({'port': freeport}, function(ph){

                return ph.createPage(function(page) {
                    return page.open("http://www.target.com/showthread.php?t="+posts[index].post_id, function(status) {
                        console.log("opened post? ", status);

                        return page.get('plainText', function(content){
                            console.log(content);
                            return ph.exit();
                        });
                    });
                });
            });
        });
    });

最佳答案

所以你是对的。这里的问题是,当您在第一个迭代(40001)上找到该端口时,在下一个迭代之前就不会消耗该端口,因此40001被发现两次。

因此,这里有2种方法。您可以使用延续,即创建下一步以执行功能,然后在占用端口后调用延续。

在这种情况下,仅跟踪端口可能会更容易。首先在40000处定义一个基本端口,找到端口后,将基本端口设置为freeport + 1并在该范围内进行搜索。

var startPort = 40000
var endPort = 60000

posts.forEach(function(element, index, posts){

    portscanner.findAPortNotInUse(startPort, endPort, 'localhost', function(err, freeport) {
        if(err) {
            return console.log(err);
        }
        console.log(freeport);

        startPort = freeport + 1 // correct the start port to search from

        phantom.create({'port': freeport}, function(ph){

            return ph.createPage(function(page) {
                return page.open("http://www.target.com/showthread.php?t="+posts[index].post_id, function(status) {
                    console.log("opened post? ", status);

                    return page.get('plainText', function(content){
                        console.log(content);
                        return ph.exit();
                    });
                });
            });
        });
    });
});


使用continuable-series的延续(未经测试,但应该可以给您一个思路)

var phantom = require("phantom")
var portscanner = require("portscanner")
var series = require("continuable-series");

module.exports = function processPosts(posts) {

    var callInSeries = posts.map(function (post) {
        return phantomPage.bind(null, post)
    });

    series(callInSeries, function (err) {
        if (err) {
            console.log(err)
        }
    }
}

function phantomPage(post, callback) {
    portscanner.findAPortNotInUse(40000, 60000, 'localhost', function(err, freeport) {
        if (err) {
            return callback(err);
        }

        phantom.create({'port': freeport}, function(ph){
            // Now that we have opened the port, we can callback immediately
            // starting the next iteration
            callback(null)

            return ph.createPage(function(page) {
                return page.open("http://www.target.com/showthread.php?t="+post.post_id, function(status) {
                    console.log("opened post? ", status);

                    return page.get('plainText', function(content){
                        console.log(content);
                        return ph.exit();
                    });
                });
            });
        });
    });
}

10-04 22:15