【问题标题】:How to create a promise which contains a canvas element如何创建一个包含画布元素的承诺
【发布时间】:2018-07-28 06:13:54
【问题描述】:

我在将缩略图生成功能转换为承诺时遇到了一些问题。

我需要它,以便它在生成缩略图后运行 Promise.all,目前拇指未定义(这是有道理的,因为它需要首先生成)。

我不明白 img.onload 的第一部分,我的解决方法是将其设置在 $scope 上,我知道这是一种糟糕的数据传递方式。

    var img = new Image;
    img.onload = resizeImage;
    img.src = $scope.imageData;

    function resizeImage() {
      var newDataUri = imageToDataUri(this, 100, 100);
      $scope.imageDataThumb = newDataUri;
      $scope.$apply();
    }
    function imageToDataUri(img, width, height) {
      // create an off-screen canvas
      var canvas = document.createElement('canvas'),
      ctx = canvas.getContext('2d');
      canvas.width = width;
      canvas.height = height;
      ctx.drawImage(img, 0, 0, width, height);
      var quality = 1.0;
      return canvas.toDataURL('image/jpeg', quality).split(",")[1];  // quality = [0.0, 1.0]
    }

    var imgGuid = factory.guid();

    //Save the image to storage
    console.log($scope.imageDataThumb);
    Promise.all([fireBaseService.postImageToStorage(imageData, "images", imgGuid), fireBaseService.postImageToStorage($scope.imageDataThumb, "images", "thumb_" + imgGuid)])
      .then(function (results) {
      //do stuff with results
      });

【问题讨论】:

  • 好像你的代码被/被剪掉了。
  • 嗨@MarkSchultheiss - 这只是保存缩略图图像的服务调用的开始
  • 当心,@Bergi 在his comment 中是正确的:您的问题是由您的一个简单的异步错误处理引起的。其实和this Q/A是同一个核心问题。如果接受的答案似乎对您有用,那仅仅是因为您尝试的图像加载时间不到 4 毫秒。对于更大的图像,您将面临同样的问题。你应该从这个答案中得到的唯一一行是“我建议也将移动图像加载到承诺中”。

标签: javascript canvas promise q


【解决方案1】:

我需要它,以便在生成缩略图后运行 Promise.all,

canvas 中的所有图像导出函数都不会返回 Promise:

toDataURL()

DOMString = canvas.toDataURL(type, encoderOptions); // 同步

toBlob()

void canvas.toBlob(callback, mimeType, qualityArgument); // 异步

唯一的方法是手动将你的函数包装到 Promise 中(虽然,对于像 toDataURL() 这样的同步函数,这没有多大意义。如果你只生成缩略图,我建议将图像加载到 Promise 中以及这更有意义,因为图像加载是异步的。):

function imageToDataUri(img, width, height) {
  return new Promise(function(success, reject) {
    // create an off-screen canvas
    var ctx = document.createElement('canvas').getContext("2d");
    ctx.canvas.width = width;
    ctx.canvas.height = height;
    ctx.drawImage(img, 0, 0, width, height);
    var quality = 1.0;
    setTimeout(function() {
      success(canvas.toDataURL('image/jpeg', quality).split(",")[1]);  //quality=[0.0,1.0]
    }, 4);  // make call async
  })
}

现在您可以将调用用作任何承诺:

var promise = imageToDataUri(img, width, height);
promise.then(function(str) { ... });

Promise.all([promise, promise2, ...])
  .then( ... );

还有一个小提示:通过将标头与 data-uri 分开,它不再是 Data-URL,而是一个 Base-64 编码的字符串 - 函数名称需要考虑。

【讨论】:

  • imageToDataUri 不是问题,确实应该保持同步。 (如果您愿意,您仍然可以使用Promise.delay(4).then(imageToDataUri) 来获得与您答案中的代码相同的效果)。问题是 OP 调用 resizeImage 作为他的图像的 onload 处理程序,但没有等待 那个
猜你喜欢
  • 2019-05-27
  • 2020-07-04
  • 2018-10-03
  • 2020-12-05
  • 2013-05-20
  • 1970-01-01
  • 2021-12-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多