使用Promise保存多个文件

时间:2016-08-27 08:31:11

标签: javascript node.js express promise

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

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

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包含在Promise.all(..)中,因为我希望saveMap()在所有地图完成下载后返回(这样我可以压缩它们并发送到调用应用程序,所以需要确保已经下载了所有内容。)

现在,我们需要扩展此功能以包括卫星地图。我希望,在同样的json迭代中,我可以有另一个下载卫星地图的Promise。像这样的东西

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文件。有人可以帮我理解我做错了什么,以及如何纠正错误。

3 个答案:

答案 0 :(得分:2)

我愿意:

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

    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);
                         })
                 })
            }), //End Array#map
            ...addressJson.map(function(item) {
                 return new Promise(function (resolve, reject) {
                     var mapUrl = 'http://maps.googleapis.com/maps/api/staticmap?maptype=satellite|' + item.address;
                     req(mapUrl)
                         .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);
                         })
                 })
            }), //End Array#map
        ])//End Promise#all
    }
    

    修改

    好的,你可能认为没有必要进行两次迭代,因为Array#reduce

    function saveMap(addressJson) {
        return Promise.all(
            //iterate over address json, get each address, call the Google Maps URL and save it.
            addressJson.reduce(function(array, item) {
              array.push(...[
                 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 mapUrl = 'http://maps.googleapis.com/maps/api/staticmap?maptype=satellite|' + item.address;
                     req(mapUrl)
                         .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);
                         })
                 })
            ]); //Array#push
            return array;
          }, []); //Array#reduce
        ) //End Promise#all
    }
    

    <强> DEMOS

    var length = 10;
    var arr1 = Array.from({length}, (el, i)=> new Promise( re => re(i) ) );
    var arr2 = Array.from({length}, (el, i)=> new Promise( re => re(i) ) );
    
    Promise.all([...arr1, ...arr2]).then(console.log.bind(console));

    var length = 10;
    var arr1 = Array.from({length}, (el, i)=> i );
    
    var finalArr = arr1.reduce((array, item)=>{
      array.push(...[
        new Promise( re => re(item) ),
        new Promise( re => re(item*2) )
      ]);
      return array;
    }, []);
    
    Promise.all(finalArr).then(console.log.bind(console));

答案 1 :(得分:1)

在该代码中有两个return语句,这就是它无效的原因。

但你真正要开始的是抽象出下载的promisification

function download(url, target) {
    return new Promise(function (resolve, reject) {
        request(uUrl).pipe(fs.createWriteStream(target))
        .on('finish', resolve)
        .on('error', reject)
    });
}

现在你可以使用它两次了。为了简单起见,我不会尝试只迭代你的数组一次,而只是map两次迭代结果。替代方案是concatMap或对每个项目的承诺进行排序。

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');
    })));
}

答案 2 :(得分:0)

再次使用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);
                     })
               })
            ]);
        })
    )
}