Javascript 如何从两个异步方法返回值?
我正在尝试创建一个没有任何第三方库的图像压缩程序 这是我的代码(它最终将返回压缩图像的blob): 我的代码似乎没有问题,但总是返回未定义的值 我发现可能是异步问题。Javascript 如何从两个异步方法返回值?,javascript,jquery,Javascript,Jquery,我正在尝试创建一个没有任何第三方库的图像压缩程序 这是我的代码(它最终将返回压缩图像的blob): 我的代码似乎没有问题,但总是返回未定义的值 我发现可能是异步问题。img.onload和canvas.toBlob是异步方法 我认为承诺可能会有所帮助,但我不知道如何对这些方法逐一运行并最终返回值进行排序 我怎样才能解决这个问题?谢谢。使用承诺而不是异步,结果是相同的,但语法上不同,在一个承诺中,您得到两个函数作为参数(通常称为解析和拒绝),这些函数可以在任何回调中运行没有问题,但是在async函
img.onload
和canvas.toBlob
是异步方法
我认为承诺
可能会有所帮助,但我不知道如何对这些方法逐一运行并最终返回值进行排序
我怎样才能解决这个问题?谢谢。使用
承诺
而不是异步
,结果是相同的,但语法上不同,在一个承诺中,您得到两个函数作为参数(通常称为解析
和拒绝
),这些函数可以在任何回调中运行没有问题,但是在async
函数中,由于无法对接收回调的函数进行等待
(因为这不是可以等待
)的承诺,因此会出现问题
TLDR;
async
函数不能很好地执行运行回调的函数,请直接使用承诺,以便可以在任何地方运行resolve()
,即使是在回调函数上
例如:
function CompressImage(File, Quality, FileType) {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var img = new Image;
var prom = new Promise(function(resolve) {
img.onload = function () {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0, img.width, img.height);
canvas.toBlob(function (blob) {
return resolve(blob);
}, FileType, Quality);
}
}
img.src = URL.createObjectURL(File);
});
return prom;
}
这就应该做到了,看看我是如何创建承诺来通过调用canvas.toBlob
解决它的,如果您注意到,函数不是async
,因为它直接返回一个承诺,但是在您的代码中,您可以像对待异步函数一样对待它
另一种方法是更新一些语法:
const CompressImage = async (File, Quality, FileType) => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const img = new Image;
return await (new Promise(resolve => {
img.onload = () => {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0, img.width, img.height);
canvas.toBlob(resolve, FileType, Quality);
}
}
img.src = URL.createObjectURL(File);
}));
};
应该是一样的
我还没有测试过这个,但是如果它坏了,就很接近了
更新:
在使用您提供的JSFIDLE之后,我有一个有趣的发现:
$(function () {
$("#FileUploader").change(function () {
StartCompress(this.files[0]);
});
function StartCompress(input) {
$("#beforesize").text(input.size);
CompressFile(input, 0.8).then(blob => $("#afteresize").text(blob.size));
}
function CompressFile(file, quality) {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var img = new Image();
var prom = new Promise(resolve => {
img.onload = () => {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
canvas.toBlob(blob => {
resolve(blob)
}, file.type, quality);
}
img.src = URL.createObjectURL(file);
});
return prom;
}
});
我修改了一点代码,这样我的强迫症就可以安然无恙了哈哈哈,但问题是MIME(FileType
),因为你没有提供canvas
文件类型,只是抓取它并将其转换为png
,这是一种无损格式,所以如果你选择jpg图像,它会更大(这允许损失)并基本上调整它以适应相同的大小
现在试试代码(我正在使用file.type
向canvas.toBlob
提供文件类型),它与png
有关,我想这与我指出的问题有关
希望有帮助。这能回答你的问题吗?@Mellet它很相似,但不一样,我必须先将文件绘制到画布上,img.onload也是异步的。@Melong了解如何等待加载图像。我尝试了上面的代码,但遇到了一个奇怪的情况:无论图像大小如何,图像的大小都会增长很多canvas.toBlob中的alityArgument是。@Melong你能在JSFIDLE上重现这个问题来帮助你吗?这是我在JSFIDLE中的代码:。奇怪的是,在JSFIDLE中,它甚至无法获得转换文件的大小。@Melong我用我的发现编辑了响应,希望它能帮助你。很好,它能工作。谢谢!
$(function () {
$("#FileUploader").change(function () {
StartCompress(this.files[0]);
});
function StartCompress(input) {
$("#beforesize").text(input.size);
CompressFile(input, 0.8).then(blob => $("#afteresize").text(blob.size));
}
function CompressFile(file, quality) {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var img = new Image();
var prom = new Promise(resolve => {
img.onload = () => {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
canvas.toBlob(blob => {
resolve(blob)
}, file.type, quality);
}
img.src = URL.createObjectURL(file);
});
return prom;
}
});