假设我有一个包含多个图片网址的数组
const imgs = [
'https://placehold.it/120x120&text=image1',
'https://placehold.it/120x120&text=image2',
'https://placehold.it/120x120&text=image3'
]
我想即时获取这些图像作为base 64字符串,以准备网络请求。要使用javascript完成此操作,我该怎么办?
我目前正在尝试:
const getDataUrl = (url) => {
return new Promise((resolve, reject) => {
let img = new Image()
let canvas = document.createElement('canvas')
img.setAttribute('crossOrigin', 'anonymous')
img.onload = function(){
canvas.height = img.height
canvas.width = img.width
canvas.getContext('2d').drawImage(img, 0, 0)
resolve(canvas.toDataUrl('png'))
}
img.src = url
})
}
let dataUrls = []
for(let img of imgs){
getDataUrl(img).then(res => {
dataUrls.push(res)
})
console.log(dataUrls)
}
但是promise不会等待图像加载和解析,而我得到一个空数组
所以我然后尝试了一个递归解决方案:
let dataUrl = ''
const getDataUrl = (url) => {
let img = new Image()
let canvas = document.createElement('canvas')
img.setAttribute('crossOrigin', 'anonymous')
img.onload = function(){
canvas.height = img.height
canvas.width = img.width
canvas.getContext('2d').drawImage(img, 0, 0)
dataUrl = canvas.toDataUrl('png')
}
img.src = url
if(checkIntegrity()) return dataUrl
}
const checkIntegrity = () => {
if(dataUrl.length > 0){
return true
}else{
return checkIntegrity()
}
}
这是不明智的,因为我不得不依赖于位于全局范围内的dataUrl,并且由于在运行此程序时遇到了太多的递归错误而无法正常工作。
最后,我想我可以尝试预定义onLoad函数并将resolve函数作为参数传递给它:
const onLoad = (img, resolve) => {
let canvas = document.createElement('canvas')
canvas.height = img.height
canvas.width = img.width
canvas.getContext('2d').drawImage(img, 0, 0)
resolve(canvas.toDataURL('png'))
}
const getDataUrl = (url) => {
return new Promise((resolve, reject) => {
let img = new Image()
img.setAttribute('crossOrigin', 'anonymous')
img.onload = onLoad(img, resolve)
img.src = url
})
}
for(let img of imgs){
getDataUrl(img).then(res => {
console.log(res)
dataUrls.push(res)
})
}
console.log(dataUrls)
这是我最成功的尝试,但是最终每次调用都返回data:,
,因此它也不起作用。这是带有该代码的小提琴:https://jsfiddle.net/5o4Lq3bh/34/
除非如此,否则我已经不知所措了。我还尝试操纵dom挂载的图像而不是javascript图像对象,并使用带有已加载检查和不同递归功能的计数器,但遇到相同错误,但递归过多。
我的主要问题似乎是迭代。我非常确定/ of是同步的,所以我猜问题是我无法将毅力nilly传递给其他函数,而期望得到有效的结果。
这在加载时很容易实现,但是它必须在运行中即时发生,我们将提供任何帮助。
答案 0 :(得分:1)
您共享的第一个代码段和第三个代码段存在一些问题。
第一个代码段,console.log始终会打印一个空数组,因为它位于then语句之外。
for(let img of imgs){
getDataUrl(img).then(res => {
dataUrls.push(res)
})
console.log(dataUrls) // will always print [] because this statement should be within then function
}
第三段,您正在调用onLoad函数,而不是将其作为事件处理程序传递
img.onload = onLoad(img, resolve) // this will call onLoad, this is not an event handler
下面的代码有效,但这没有利用promises的全部功能
const getDataUrl = (url) => {
return new Promise((resolve, reject) => {
let img = new Image()
img.setAttribute('crossOrigin', 'anonymous')
img.onload = function(){
let canvas = document.createElement('canvas')
canvas.height = img.height
canvas.width = img.width
canvas.getContext('2d').drawImage(img, 0, 0)
let b64String = canvas.toDataURL('png');
resolve(b64String)
}
img.src = url
})
}
for(let img of imgs){
getDataUrl(img).then(res => {
dataUrls.push(res)
console.log(dataUrls.length)
})
}
如果您想要一种更清晰的方法,请使用以下
const imgs = [
'https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/pie.png',
'https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/pie.png',
'https://s3-us-west-2.amazonaws.com/s.cdpn.io/3/pie.png'
]
let dataUrls = []
let images = [];
for(let imgUrl of imgs){
images.push(new Promise((resolve, reject) => {
let img = new Image();
img.setAttribute('crossOrigin', 'anonymous')
img.onload = function(){
let canvas = document.createElement('canvas')
canvas.height = img.height
canvas.width = img.width
canvas.getContext('2d').drawImage(img, 0, 0)
let b64String = canvas.toDataURL('png');
dataUrls.push(b64String);
resolve(b64String)
}
img.src = imgUrl
}));
}
Promise.all(images).then(function(){
console.log(dataUrls)
})
https://jsfiddle.net/karthick6891/5o4Lq3bh/52/
注意:仅供参考,您的小提琴也没有为我工作,我遇到了与所有人一样的跨源问题。