在JavaScript中使用承诺创建异步函数
我有一个函数在JavaScript中使用承诺创建异步函数,javascript,node.js,asynchronous,promise,axios,Javascript,Node.js,Asynchronous,Promise,Axios,我有一个函数 function getImage(url, key) { return axios({ method: 'get', url, responseType: 'stream' }).then(response => { s3.upload({ Key: key, Body: response.data, ContentType: response.data.headers['content-type'
function getImage(url, key) {
return axios({
method: 'get',
url,
responseType: 'stream'
}).then(response => {
s3.upload({
Key: key,
Body: response.data,
ContentType: response.data.headers['content-type'],
ACL: 'public-read'
}, (err, data) => {
return key
});
}).catch(err => {
return '';
});
}
它下载一个远程图像并上传到AmazonS3。我希望它返回生成的密钥
我想使用这样的函数
const images = ['http://...', 'http://...', ...].map((url, i) => {
return {
url: getImage(url, i)
}
});
由于我的函数getImage()
对于每个URL都可能需要一段时间,因此我想我必须使用异步调用,以便在继续下一个元素之前(或者我误解了什么?)
我想我必须使用承诺,所以解决方案可能是这样的吗
function getImage(url, key) {
return new Promise((resolve, reject) => {
return axios({
method: 'get',
url,
responseType: 'stream'
}).then(response => {
s3.upload({
Key: key,
Body: response.data,
ContentType: response.data.headers['content-type'],
ACL: 'public-read'
}, (err, data) => {
resolve(key);
});
}).catch(err => {
reject(err);
});
});
}
然后像这样使用它:
const images = ['http://...', 'http://...', ...].map((url, i) => {
return {
url: getImage(url, i).then(url => url).catch(err => [])
}
});
编辑
正如评论中提到的,axios是一个承诺。那么代码应该是这样的吗
function getImage(url, key) {
return axios({
method: 'get',
url,
responseType: 'stream'
}).then(response => {
return new Promise((resolve, reject) => {
s3.upload({
Key: key,
Body: response.data,
ContentType: response.data.headers['content-type'],
ACL: 'public-read'
}, (err, data) => {
if (!err) {
resolve(key);
} else {
reject(err);
}
});
});
});
}
编辑2
用例是我从一个公共API获取了很多博客文章。所以我在做类似的事情
const blogPostsOriginal = [
{ title: 'Title', images: ['url1', 'url2'] },
{ title: 'Title', images: ['url1', 'url2'] },
{ title: 'Title', images: ['url1', 'url2'] },
];
const blogPostsFormatted = blogPostsOriginal.map(blogPost => {
return {
title: blogPost.title,
images: blogPost.images.map(url => {
// upload image to S3
return getImage(url);
})
};
});
那么,我将如何构造博客文章数组的格式呢?问题是,如果发生错误,我不想将图像包含在图像数组中。我不知道如何用承诺来检验这一点。使用ECMAScript 2017语法,您可以非常轻松地完成这一点。修改脚本的原始形式(您声称它正在工作),它将如下所示:
异步函数getImage(url,键){
试一试{
常数响应=等待axios({
方法:“get”,
网址,
响应类型:'stream'
})
等待s3.0上传({
钥匙:钥匙,
正文:response.data,
ContentType:response.data.headers['content-type'],
ACL:“公共读取”
}).承诺
}捕获(错误){
//返回错误
return key//因为这里没有axios和s3
}
返回键
}
常量blogpostoriginal=[
{title:'title',图像:['url1','url2']},
{title:'title',图像:['url1','url2']},
{title:'title',图像:['url1','url2']},
];
Promise.all(blogpostoriginal.map)(异步({title,images})=>{
返回{
标题
images:(等待Promise.all(images.map)(异步(url)=>{
//把你的钥匙拿过来
const key=Math.random().toString(36).slice(2,12).padStart(10,0)
//将图像上载到S3
返回getImage(url,键)
})))
//等待结果数组后,过滤掉错误
.filter(结果=>!(错误的结果实例))
}
}))。然后(blogPostsFormatted=>{
//使用此处格式的BlogPosts
console.log(blogpostsformated)
})使用ECMAScript 2017语法,您可以非常轻松地完成此任务。修改脚本的原始形式(您声称它正在工作),它将如下所示:
异步函数getImage(url,键){
试一试{
常数响应=等待axios({
方法:“get”,
网址,
响应类型:'stream'
})
等待s3.0上传({
钥匙:钥匙,
正文:response.data,
ContentType:response.data.headers['content-type'],
ACL:“公共读取”
}).承诺
}捕获(错误){
//返回错误
return key//因为这里没有axios和s3
}
返回键
}
常量blogpostoriginal=[
{title:'title',图像:['url1','url2']},
{title:'title',图像:['url1','url2']},
{title:'title',图像:['url1','url2']},
];
Promise.all(blogpostoriginal.map)(异步({title,images})=>{
返回{
标题
images:(等待Promise.all(images.map)(异步(url)=>{
//把你的钥匙拿过来
const key=Math.random().toString(36).slice(2,12).padStart(10,0)
//将图像上载到S3
返回getImage(url,键)
})))
//等待结果数组后,过滤掉错误
.filter(结果=>!(错误的结果实例))
}
}))。然后(blogPostsFormatted=>{
//使用此处格式的BlogPosts
console.log(blogpostsformated)
})当您调用
getImage
时,它会通过axios
创建一个承诺。如果您想对不同的URL多次使用它,那么您就可以了,因为每个承诺都会在解决后返回。在这种情况下,在Promise对象中包装axios
是多余的。啊,我明白了。我已经更新了我的问题,当您调用getImage
时,它通过axios
创建承诺。如果您想对不同的URL多次使用它,那么您就可以了,因为每个承诺都会在解决后返回。在这种情况下,在Promise对象中包装axios
是多余的。啊,我明白了。我已经更新了我的问题,谢谢!看起来不错,但我仍然不确定如何用我的用例实现它。在我的第二次编辑中,你能帮我回答我的问题吗?另一个简短的问题。您的原始代码在未获取或上载的图像上以静默方式失败,并返回一个空白字符串作为密钥。修改后的代码返回单个承诺,这些承诺根据其成功与否而定,但您没有任何东西等待它们集体实现,这就是为什么我使用了Promise.all()
,但如果其中任何一个失败,这将导致所有承诺都失败。这样可以吗?如果一个映像失败,我只希望它从阵列中删除。因此,我将尽可能多地保留图像。我想如果出现这种情况,我将不得不返回null
,然后使用.filter(element=>!!element)
或类似的方法来删除那些不起作用的内容,但是当我使用图像时,这似乎有点像黑客:(等待Promise.all(blogPost.images.map(async(url)=>getImage(url)).filter(result=>(result instanceof Error)),
,我得到了语法错误:意外标识符
注意我答案中wait
周围的括号。这些是必须的,谢谢!看起来不错,但我仍然不确定如何用我的用例实现它。在我的第二次编辑中,你能帮我回答我的问题吗?另一个简短的问题。您的原始代码在未获取或上载的图像上以静默方式失败,并返回一个空白字符串作为密钥。修改后的代码返回单个承诺,这些承诺根据成功与否而定,但您没有任何东西等待它们的实现