当前位置: 首页 > 知识库问答 >
问题:

使用javascript,如何等待所有.toblob函数完成后再继续?

宗乐池
2023-03-14

我正在使用JavaScript处理图像。对于每个图像,我使用.toblob创建4个文件。问题在于.toblob是异步的,这样一个.toblob进程可以在其他进程完成时运行。await异步似乎不起作用。处理的图像数的计数器似乎不起作用,因为上一个图像可以处理,而前一个图像尚未完成。最后一个图像将计数器增加到图像数并触发保存。

我可以在最后一个图像上做一个setTimeout,但那只是在猜测最大时间。

代码如下:

let kpData;
let repositoryData;
let collection;
let skuString = `,`;
let numImages;
let numImagesProcessed;
$(document).on(`click`, `.saveSkuImages`, function() {
    numImagesProcessed = 0;
    kpData = new FormData();
    repositoryData = new FormData();
    skuString = `,`;
    const skuContainer = $(this).closest(`.skuContainer`);
    const sku = skuContainer.attr(`sku`);
    numImages = skuContainer.find(`.skuImgContainer`).length;
    let i = 0;
    skuContainer.find(`.skuImgContainer`).each(function() {
        i++;
        sic = $(this);
        const skuImg = sic.find(`.skuImg`);
        const imgContainer = skuImg.find(`.imgContainer`);
        const img = imgContainer.find(`img:first`);
        cvs = $(`#${img.attr(`forcanvas`)}`);
        imgNum = parseInt(skuImg.attr(`imgnum`));
        const filename = `${sku}${imgNum > 1 ? `-alt${imgNum}` : ``}.jpg`;
        img.attr(`filename`, filename);
        if (cvs.length) { 
            createImages(cvs[0], imgNum, filename,i);
        } else { //if an image already exists, we didn't create a canvas for it and we don't need to recreate it.
            numImagesProcessed++;
        }
        if (sic.find(`.useForSeasonal`).is(`:checked`)) {
            kpData.append(`parentImage`, filename);
        }
    });
});

sgiArr = [`L`, `LI`, `I`, `K`, `Y`];

function createImages(loadedData,imgNum,filename,i) {
    const mime_type = `image/jpeg`;
    var cvs = document.createElement(`canvas`);
    //Create the detail version of the image
    cvs.width = 800;
    cvs.height = 800;
    ctx = cvs.getContext(`2d`);
    ctx.drawImage(loadedData, 0, 0, 800, 800);
    if (imgNum === 1 && sgiArr.indexOf(filename.split(`-`)[2]) >= 0) {
        // attach the size watermark to our primary image if it's a kid's product
        let watermark = document.getElementById(`sgi${filename.split(`-`)[2]}`);
        ctx.drawImage(watermark, 10, 720);
    }

    const newImageData = cvs.toDataURL(mime_type);
    const result_image_obj = new Image();
    result_image_obj.src = newImageData;
    if (imgNum === 1 && sgiArr.indexOf(filename.split(`-`)[2]) >= 0) {
        // display the image if we've attached the size watermark to it
        $(`img[filename="${filename}"]`).attr(`src`, result_image_obj.src);
    }
    cvs.toBlob((blob) => {
        let file = new File([blob], filename, { type: `image/jpeg` });
        kpData.append(`detail`, file, filename);
    }, `image/jpeg`,0.96);

    //create the general image
    cvs.width = 370;
    cvs.height = 370;
    cvs.getContext(`2d`).drawImage(loadedData, 0, 0, 370, 370);
    cvs.toDataURL(mime_type);
    cvs.toBlob((blob) => {
        let file = new File([blob], filename, { type: `image/jpeg` });
        kpData.append(`general`, file, filename);
    }, `image/jpeg`,0.96);

    //create the thumbnail
    cvs.width = 240;
    cvs.height = 240;
    cvs.getContext(`2d`).drawImage(loadedData, 0, 0, 240, 240);
    cvs.toDataURL(mime_type);
    cvs.toBlob((blob) => {
        let file = new File([blob], filename, { type: `image/jpeg` });
        kpData.append(`thumb`, file, filename);
    }, `image/jpeg`,0.96);

    //create the repository image for Amazon, Zulilly, Zappos and our wholesale customers. Zullily has the greatest minimum requirements so we'll use those for everyone
    loadedData.toBlob((blob) => {
        let file = new File([blob], filename, { type: `image/jpeg` });
        repositoryData.append(`imgfiles`, file, filename);
        numImagesProcessed++;
        console.log(`repository data created: `, numImagesProcessed, imgNum);
        if (numImagesProcessed === numImages) { // the process can get to here yet not all the previous .toBlob statments from previous images may have completed.
            console.log(`finished. Trigger save`);
            saveit();
        }
    }, `image/jpeg`, 0.92);
}

我试过用一系列的承诺:

skuContainer.find(`.skuImgContainer`).each(function() {
    promises.push(processSku($(this),sku));
});
$.when.apply($, promises).done(function() {
    console.log(`promises are done:`,numFiles, numFilesCreated);
    saveit();
});

那就更糟了。done函数甚至在第二次迭代完成之前就启动了。我尝试在每个.toblob函数中递增一个计数器,但计数器没有在“if(counter===NumFileStocreate)saveIt();”的时间内递增

我不知所措。

谢谢

共有1个答案

夹谷阳夏
2023-03-14

您很可能希望使用promise.all方法。我知道你在评论中说它不起作用,但我想展示一个起作用的例子。如果这在您的实例中不起作用,那么为了在这个论坛上获得帮助,创建一个演示您的确切问题的MRE可能是最有益的。一些可以运行的东西。

null

var promisesArray = [
  new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('promise 1 done!');
      resolve('');
    }, 300);
  }),
  new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('promise 2 done!');
      resolve('');
    }, 5);
  }),
  new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('promise 3 done!');
      resolve('');
    }, 50);
  }),
  new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('promise 4 done!');
      resolve('');
    }, 500);
  })
];

async function ResolveAll() {
  await Promise.all(promisesArray);
  console.log('after all promises');
}

ResolveAll();
 类似资料:
  • 问题内容: 我过去一直在努力,今天一直在努力的事情是阻止API / AJAX继续进行,直到您收到响应为止。目前,我正在使用Facebook API。我需要从调用中获取响应,然后将其返回,但是正在发生的事情是,在我从未从API调用中获取响应之前,我的函数正在返回。我知道为什么会这样,我只是想不出如何预防!这是我的代码… // -----编辑 我注意到有人建议这样的事情… 但这返回未定义 //根据更新

  • 问题内容: 为什么每当我将ajax放入for循环中时,它都无法很好地同步? 例如,我的代码是: 为什么它先调用Ajax查询?是否有可能让ajax查询在继续之前完成?因为它在完成填充之前就清除了数组。:/ 问题答案: 首先,您确实需要了解Ajax调用是如何异步的(这就是Ajax中的“ A”所代表的意思)。这意味着调用仅启动ajax调用(它将请求发送到服务器),其余代码愉快地继续运行。有时,在其余代码

  • 问题内容: 我的document.ready()中有一些ajax调用 喜欢 : 我如何强制它等待,直到我们从ajax请求获得所有回叫之前不继续? 问题答案: 我根本不喜欢任何答案,最好的方法(自Jquery 1.5+起)是使用Deferred对象,这些是操纵异步调用的对象,可以解决: 这样,myFunc会在执行2个ajax调用之后执行,如果其中一个出错,则执行myFailure。 您可以在jque

  • 问题内容: 我需要一次执行一些任务4,如下所示: 全部完成后如何获得通知?现在,我想不出什么比设置一些全局任务计数器并在每个任务结束时减少它,然后无限循环监视此计数器为0更好的了。或获取期货的列表,并在无限循环中对所有期货进行isDone监视。什么是不涉及无限循环的更好的解决方案? 问题答案: 基本上在你致电之后:

  • 我有一个简单的Java程序,它使用SpringWebClient发送多个请求。每个都返回一个mono,我使用的是response。subscribe()以检查结果。 但是,我的主执行线程在处理所有请求之前完成,除非我添加一个长线程。睡眠()。 对于CompletableFutures,您可以使用:CompletableFuture。allOf(期货)。join(); 有没有办法等待所有单声道的完成

  • 问题内容: 这是我的代码段。 现在做完之后 我要在这里实现的是,我要等待线程池中的所有线程完成执行,然后关闭执行器。 但是我想这不是这里正在发生的事情。主线程似乎正在执行关闭,它只是关闭了所有内容。 在我的线程池大小为2之前,我做了以下事情,而且似乎可行。 我如何在线程池中使用更多线程?谢谢。 问题答案: 您通常使用以下成语: 只是说执行者不会接受新工作。 等待直到所有已提交的任务完成它们的工作(