我有一个节点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文件。有人可以帮我理解我做错了什么,以及如何纠正错误。
答案 0 :(得分:2)
我愿意:
看看它的外观:(注意使用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);
})
})
]);
})
)
}