【问题标题】:A dictionary of deferred promises延迟承诺字典
【发布时间】:2016-12-08 14:11:22
【问题描述】:

我需要用图像构建 PDF。我认为可以提供指向本地存储文件的链接,但是(请纠正我,我会很高兴)结果证明 PDFmake 只能处理 data:URI 编码的图像。
所以现在我必须转换图像,但必须先加载它们,否则我将转换为空白。

想法是将PDF构建代码放在
$.when.apply(null, imgData).done(function() { });的括号中
AFAIK,图像可以随机加载,因此为了防止弄乱它们的顺序,我将它们放入字典中,其中每个值的键是初始 imgSources 数组的索引。
现在,这是我第一次使用Deferred 类和$.when,所以请纠正我的错误用法。

function toDataUrl(src) {
    var img = new Image(),
    deferred = $.Deferred();
    img.crossOrigin = 'Anonymous';
    img.onload = function() {
        var canvas = document.createElement('CANVAS');
        var ctx = canvas.getContext('2d');
        var dataURL;
        canvas.height = this.height;
        canvas.width = this.width;
        ctx.drawImage(this, 0, 0);
        dataURL = canvas.toDataURL('image/jpeg');
        deferred.resolve(dataURL);
    };
    img.src = src;
    return deferred.promise();
}

function makepdf() {
    var pdfContent, a = [], b = [], kontent = [],
        list = $("#tabs ul>li a"),
        imgSources = ['images/weledu.jpg'],
        imgData = {};
    $.getJSON(get_url+'types.php?id='+$('#type').val(), function (newsrc) {
        imgSources.push('images/lamps/'+newsrc.data['0'].image);
        $.each(imgSources, function(index, src) {
            imgData.index = toDataUrl(src);
        });
    });

    $.when.apply(null, imgData).done(function() {
        // pdf creation
    });     
};

如果我在传递给.done() 的回调中放置一个断点,imgData 对象仍然是空白的!我错在哪里?不是应该完成吗?

【问题讨论】:

  • Function.prototype.apply 不应用对象,它应用数组。
  • @zzzzBov 很好,但是我如何确定我现在从结果数组中取出了哪个 imag 的 URI?我很乐意接受建议
  • 查看您正在解决的整体问题,您最好上传图像并创建 PDF 服务器端。我们在我们的商业应用中这样做。
  • @GoneCoding 等等。第一件事 - 图像存储在服务器上,没有“上传”。第二件事 - 请更好地解释“服务器端”,我不明白。你的意思是使用 PHP 和它的库来创建 PDF 还是?
  • 是的,使用服务器端库来创建 PDF。将它们全部移至客户端浏览器,只是为了处理 PDF,似乎解决这个问题还有很长的路要走,但是嘿,它是 PHP :)

标签: jquery promise jquery-deferred


【解决方案1】:

这里有几个问题。一是您不能将$.when.apply 与对象(字典)一起使用,只能用于数组。另一个是当你调用$.when.apply时,你的AJAX调用还没有完成,所以imgData里面甚至没有任何数据。

发生的情况是,当您将 empty 对象传递给 $.when.apply 时,它将被视为已解决的承诺(就像您在没有参数的情况下调用 $.when() 一样),因此立即调用您的.done() 方法。这一切都发生在之前 $.getJSON 完成。 (请参阅$.when 的文档:https://api.jquery.com/jQuery.when/

还有一点需要注意的是,在 JavaScript 中,对象是无序的,也就是说你不能总是保证每次都以相同的顺序循环它。为了保证顺序,您需要一个数组。

还要提一提的是imgData.index = toDataUrl(src); 并没有按照你的想法去做。这会向您的对象添加一个名为 "index" 的键,它不使用 index。要执行您所期望的操作,请使用 imgData[index] = toDataUrl(src);

因此,这里的一种解决方案是将您的$.when.apply 放入您的$.getJSON 并将imgData 更改为一个数组。

注意$.when保持您传递给它的参数的顺序(或者在这种情况下是您“应用”到它的数组)。在.done() 回调中,您将按正确顺序传递参数(dataURL 值)。

function makepdf() {
    var pdfContent, a = [], b = [], kontent = [],
        list = $("#tabs ul>li a"),
        imgSources = ['images/weledu.jpg'],
        imgData = [];

    $.getJSON(get_url+'types.php?id='+$('#type').val(), function (newsrc) {
        imgSources.push('images/lamps/'+newsrc.data['0'].image);

        $.each(imgSources, function(index, src) {
            imgData.push(toDataUrl(src));
        });

        // I've always passed `$` as the 1st parameter here, 
        // not sure if it matters
        $.when.apply($, imgData).done(function(img1, img2) {
            // pdf creation
            // Use `img1`, `img2`, etc. here
            // Or loop over `arguments` to get the `dataURL`s
        });     
    });
}

【讨论】:

  • 加载顺序如何?它仍然无法预测。此外,您对键没有了解我的想法:我不打算通过生成的 dict 循环,而是要访问精确的元素,因为它们的键与初始数组的顺序相同。我不沉迷于字典,很乐意改用数组,请向我保证订单将被保留
  • “加载顺序”是什么意思?你的意思是toDataUrl() 可以先完成一张图片?
  • 是的,我的意思是加载顺序,有点
  • 订单将被保留,请查看$.when (api.jquery.com/jQuery.when) 的文档。在您的.done() 回调中,它将按照延迟传递给它的顺序传递参数。
猜你喜欢
  • 2015-03-08
  • 2015-03-27
  • 2023-03-21
  • 1970-01-01
  • 1970-01-01
  • 2013-09-11
  • 2016-12-08
  • 2015-08-25
相关资源
最近更新 更多