Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/391.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何从两个异步方法返回值?_Javascript_Jquery - Fatal编程技术网

Javascript 如何从两个异步方法返回值?

Javascript 如何从两个异步方法返回值?,javascript,jquery,Javascript,Jquery,我正在尝试创建一个没有任何第三方库的图像压缩程序 这是我的代码(它最终将返回压缩图像的blob): 我的代码似乎没有问题,但总是返回未定义的值 我发现可能是异步问题。img.onload和canvas.toBlob是异步方法 我认为承诺可能会有所帮助,但我不知道如何对这些方法逐一运行并最终返回值进行排序 我怎样才能解决这个问题?谢谢。使用承诺而不是异步,结果是相同的,但语法上不同,在一个承诺中,您得到两个函数作为参数(通常称为解析和拒绝),这些函数可以在任何回调中运行没有问题,但是在async函

我正在尝试创建一个没有任何第三方库的图像压缩程序

这是我的代码(它最终将返回压缩图像的blob):

我的代码似乎没有问题,但总是返回未定义的值

我发现可能是异步问题。
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;  
    }
});