使用NodeJS下载数百万图像

时间:2015-01-06 06:23:31

标签: javascript node.js asynchronous

我正在开发一个节点应用程序,它将从地图服务器下载数百万个地图图块(图像),并且图块的网址将由x和y的缩放级别和坐标动态生成,以下是代码:

var tpl_url="http://tile.server.com/{z}/{x}/{y}.png";
var z= 19 ,x_range=[0,10000],y_range=[0,10000],down_dir="download";
function generateUrl(z,x,y){
    var obj={x:x,y:y,z:z};
    return tpl_url.replace(/\{(\w+)\}/g,function(a,key){
        return obj[key];
    });
}
function generateFilePath(z,x,y){
    return path.join(down_dir,z.toString(),x.toString(),y+".png");
}
function download(url,path,callback){
    request(url).pipe(fs.createWriteStream(path)).on('error',function(e){
        callback && callback(e,url);
    }).on('close',function(){
        callback && callback(null,url);
    });
}
var num = 0;
function onTileLoaded(err,url){
    console.log(url+"\t " + (!err?"complete ":"error") + (++num));
}

for(var i=x_range[0];i<=x_range[1];i++){
    for(var k=y_range[0];k<=y_range[1];k++){
        var x = i,y = k;
        var  url = generateUrl(z,x,y);
        var filePath = generateFilePath(z,x,y);
        fs.exists(path.dirname(filePath),function(exists){
            if(!exists){
                mkdirp(path.dirname(filePath),function(){
                    download(url,filePath,onTileLoaded);
                });
            }else{
                download(url,filePath,onTileLoaded);
            }
        });
        console.log("iterator:" + i + "," + k);
    }
}

现在我遇到了三个问题:

1覆盖变量值

很明显,这不起作用,因为fs.exists是异步操作,当操作完成时,url filePath之类的变量将被下一个循环覆盖,通常我会关闭闭包这些变量如下:

for(var i...){
    for(var k...){
            var x = i,y = k;
            var  _url = generateUrl(z,x,y);
            var _filePath = generateFilePath(z,x,y);
            (function(url,filePath){
                fs.exists(path.dirname(filePath),function(exists){
                    if(!exists){
                        mkdirp(path.dirname(filePath),function(){
                            download(url,filePath,onTileLoaded);
                        });
                    }else{
                        download(url,filePath,onTileLoaded);
                    }
                });
            })(_url,_filePath);

        console.log("iterator:" + i + "," + k);
    }
}

它有效,但似乎这意味着一旦有异步函数调用,我必须通过自动执行的匿名函数进行闭包,我认为这是不方便的。

所以我想知道你是如何解决这类问题的?

2异步操作的执行时间

似乎除非循环完成,否则不会执行异步操作,因此在我的示例中,我必须等待10000*10000次循环。

我找不到解决方案。

3多线程支持

通常我会创建多个线程来下载Java,C#中的图像,是否可以在NodeJS中使用?

1 个答案:

答案 0 :(得分:0)

要回答第3点,node.js是单线程的。但是你可以使用异步代码和回调来同时下载多个磁贴 - 你的循环可以继续下一次,而前一个仍在下载,并且每次下载完成后都会被中断以处理回调函数。