Javascript 使用Promise保存多个文件

Javascript 使用Promise保存多个文件,javascript,node.js,express,promise,Javascript,Node.js,Express,Promise,我有一个节点URL(使用Express创建),可用于下载地址的静态图像。因此,调用应用程序调用/download url并使用json传递多个地址,然后下载服务将调用Google Maps并在节点服务器上保存每个addrese的静态图像(然后它会将其发送回调用应用程序,但出于这个问题的目的,我只对在节点服务器中保存图像感兴趣) 最初,我们只对保存地址的卫星视图感兴趣,所以我编写了这段代码 var request = require('request'); function saveMap(add

我有一个节点URL(使用Express创建),可用于下载地址的静态图像。因此,调用应用程序调用/download url并使用json传递多个地址,然后下载服务将调用Google Maps并在节点服务器上保存每个addrese的静态图像(然后它会将其发送回调用应用程序,但出于这个问题的目的,我只对在节点服务器中保存图像感兴趣)

最初,我们只对保存地址的卫星视图感兴趣,所以我编写了这段代码

var request = require('request');
function saveMap(addressJson) {
    return Promise.all(
        //iterate over address json, get each address, call the Google Maps URL and save it.
        addressJson.map(function(item) {
             return new Promise(function (resolve, reject) {
                 var mapUrl = 'http://maps.googleapis.com/maps/api/staticmap?maptype=roadmap&markers=size:mid|color:red|' + item.address;
                 request(mapUrl)
                     .pipe(fs.createWriteStream('/temp/' + item.id + '.jpg'))
                     .on('finish', function () {
                         resolve("Promise resolved");
                     }).on('error', function (error) {
                         reject('Error in creating map', error);
                     })
             });
        })
    )
}
保存每个地址的承诺被包装在Promise.all(..)中,因为我想在所有地图下载完成后返回saveMap()(这样我就可以压缩它们并发送到调用的应用程序,所以需要确保所有内容都已下载)

现在,我们需要扩展这个函数来包括卫星地图。我希望,在相同的json迭代中,我可以有另一个承诺,下载卫星地图。类似这样的东西

function saveMap(addressJson) {
    return Promise.all(
        //iterate over address json, get each address, call the Google Maps URL and save it.
        addressJson.map(function(item) {
             return new Promise(function (resolve, reject) {
                 var mapUrl = 'http://maps.googleapis.com/maps/api/staticmap?maptype=roadmap|' + item.address;
                 request(mapUrl)
                     .pipe(fs.createWriteStream('/temp/r/' + item.id + '.jpg'))
                     .on('finish', function () {
                         resolve("Promise resolved");
                     }).on('error', function (error) {
                         reject('Error in creating map', error);
                     })
             });
             return new Promise(function (resolve, reject) {
                 var mapUrl2 = 'http://maps.googleapis.com/maps/api/staticmap?maptype=satellite|' + item.address;
                 req(mapUrl2)
                     .pipe(fs.createWriteStream(fs.createWriteStream('/temp/s/' + item.id + '.jpg'))
                     .on('finish', function () {
                         resolve("Promised resolved");
                     }).on('error', function (error) {
                         reject('Error in creating map', error);
                     })
             });
        })
    )
}
但是,这并没有按预期工作。我没有收到错误,但它没有生成所有jpg文件。请有人帮助我了解我做错了什么,以及如何更正此错误。

只需再次使用
Promise.all()

function saveMap(addressJson) {
    return Promise.all(
        //iterate over address json, get each address, call the Google Maps URL and save it.
        addressJson.map(function(item) {
             return Promise.all([
               new Promise(function (resolve, reject) {
                 var mapUrl = 'http://maps.googleapis.com/maps/api/staticmap?maptype=roadmap|' + item.address;
                 request(mapUrl)
                     .pipe(fs.createWriteStream('/temp/r/' + item.id + '.jpg'))
                     .on('finish', function () {
                         resolve("Promise resolved");
                     }).on('error', function (error) {
                         reject('Error in creating map', error);
                     })
               }),
               new Promise(function (resolve, reject) {
                 var mapUrl2 = 'http://maps.googleapis.com/maps/api/staticmap?maptype=satellite|' + item.address;
                 req(mapUrl2)
                     .pipe(fs.createWriteStream(fs.createWriteStream('/temp/s/' + item.id + '.jpg'))
                     .on('finish', function () {
                         resolve("Promised resolved");
                     }).on('error', function (error) {
                         reject('Error in creating map', error);
                     })
               })
            ]);
        })
    )
}
我会:

  • 生成一个包含所有承诺的数组
  • 使用一个Promise.all()调用完整的promises数组
  • 看看它的外观:(注意使用运算符连接两个数组):

    编辑

    好的,您可能认为不需要两次迭代,因为:

    演示

    var长度=10;
    var arr1=Array.from({length},(el,i)=>newpromise(re=>re(i));
    var arr2=Array.from({length},(el,i)=>newpromise(re=>re(i));
    
    Promise.all([…arr1,…arr2])。然后(console.log.bind(console));
    在该代码中有两个
    return
    语句,这就是它不起作用的原因

    但是,您真正应该首先从下载中提取您的内容:

    function download(url, target) {
        return new Promise(function (resolve, reject) {
            request(uUrl).pipe(fs.createWriteStream(target))
            .on('finish', resolve)
            .on('error', reject)
        });
    }
    
    现在您可以使用它两次。简单地说,我不会尝试只迭代一次数组,而是简单地将其映射两次并对结果进行concat。另一种方法是对每个项目的承诺进行排序

    function saveMap(addressJson) {
        var mapUrl = 'http://maps.googleapis.com/maps/api/staticmap?maptype=';
        return Promise.all(addressJson.map(function(item) {
            return download(mapUrl + 'roadmap|' + item.address, '/temp/r/' + item.id + '.jpg');
        }).concat(addressJson.map(function(item) {
            return download(mapUrl + 'satellite|' + item.address, '/temp/s/' + item.id + '.jpg');
        })));
    }
    

    一旦您
    返回
    某个内容,函数就执行完毕。您需要将第一个
    resolve
    调用替换为第二个promise回调的内容。这不会使两个promise(一个用于路线图,另一个用于卫星地图)按顺序运行吗?
    function download(url, target) {
        return new Promise(function (resolve, reject) {
            request(uUrl).pipe(fs.createWriteStream(target))
            .on('finish', resolve)
            .on('error', reject)
        });
    }
    
    function saveMap(addressJson) {
        var mapUrl = 'http://maps.googleapis.com/maps/api/staticmap?maptype=';
        return Promise.all(addressJson.map(function(item) {
            return download(mapUrl + 'roadmap|' + item.address, '/temp/r/' + item.id + '.jpg');
        }).concat(addressJson.map(function(item) {
            return download(mapUrl + 'satellite|' + item.address, '/temp/s/' + item.id + '.jpg');
        })));
    }