【问题标题】:How to wait until all the promises finish如何等到所有的承诺完成
【发布时间】:2020-10-08 20:28:35
【问题描述】:

假设,我们想在上传图片之前检查它的宽度。 Here is the fiddle。最后我们需要等待所有异步操作结束。为此,我尝试使用 Promises。但是,不幸的是,good_images 在 alert 中是空的。看来,我错过了一些简单的东西。

我尝试了 Promise.all,但它也不起作用。 Fiddle.

$(document).ready(function () {
    function check_image_dimensions ($this, image, img_name) {

        let min_width = + $this.data('min_width');
        if (typeof(min_width) === "number" && image.width < min_width) {
            alert(`Error loading photo ${img_name}, image width: ${image.width}px is less then minimal: ${min_width}px.`);
            return false;
        }

        return true;
    }

    function unknown_error () {
        alert('Unknown error while loading image.');
    }

    $(document).on('change', '.upload_images', function() {
        var $this = $(this);
        let images = $this.prop('files');
        if (typeof(images) === 'undefined' || images.length === 0) {
            return false;
        }

        let good_images = Array();
        let promise = Promise.resolve();// <- I tried this, but it is wrong
        for (let i = 0; i < images.length; i++) {
            let promise = new Promise(function(resolve, reject) {
                const reader = new FileReader();
                reader.onload = resolve;
                reader.readAsDataURL(images[i]);
            });

            promise.then((event) => {
                const img  = new Image();
                img.onload = () => {
                    if(check_image_dimensions($this, img, images[i].name) === true) {
                        good_images.push(i);
                    }
                };

                img.onerror = unknown_error;
                img.src = event.target.result;
                return i;
            }).catch(unknown_error);
        }

        promise.then(() => alert(good_images));
    });
});

【问题讨论】:

  • 您的小提琴似乎与您在此处发布的代码关系不大。不过,我可以为您在问题中的上述代码回答您的问题。
  • @ChrisAdams 我试图将所有承诺推入一个数组,然后运行 ​​Promises.all,但它也给出了一个空警报。你想让我把代码贴在这里吗?
  • @RobinZigmond Ops,抱歉,旧版本。小提琴已更新。
  • 实际上我发现将其转换为使用 Promise.all 并不像我想象的那么简单,因为该数组不仅在所有承诺解决之后才填充,而且在所有图像 @987654326 之后才填充@ 事件已触发。请问这段代码的实际目的是什么?仅仅获得一组索引并不会让我觉得你真正想要的最终产品。

标签: javascript asynchronous callback


【解决方案1】:

如果您想并行处理所有这些图像,您可以创建一个 promise 数组并使用 Promise.all 等待它们。请注意,在处理图像时,您还需要将该部分包装在 Promise 中:

const good_images = [];
const promises = [];
for (let i = 0; i < images.length; I++) {
  const image = images[I];
  let promise = new Promise( ... );

  promise = promise.then((event) => {
    const img = new Image();
    img.src = event.target.result;

    return new Promise(resolve => {
      img.onload = () => {
        if (is_good(img)) {
          good_images.push(i);
        }
        resolve();
      };
    });
  })

  promise = promise.catch(() => { ... });

  promises.push(promise);
});

Promise.all(promises).then(() => alert(good_images));

【讨论】:

  • images.map(...) 在这里不起作用,因为images 是一个文件列表,而不是一个数组。
  • 更新了我的答案,将FileList 转换为数组。另见:stackoverflow.com/questions/25333488/…
  • 是的,它有效。是否可以使用旧的 for 循环而不是 map 来做到这一点?我试过了,但是 good_images 还是空的。
  • 当然。 FileList 应该是可迭代的,因此这种方法很有意义,尤其是在您不想进行数组转换的情况下。在你的 for 循环之前,创建一个空的 promise 数组。在你的 for 循环中,将我们当前返回的 Promise 推送到你的 Promise 数组中。如果您遇到困难并需要我更新我的答案,请告诉我。
  • 我卡住了,自己尝试了 2 个小时。你能用 for 循环展示第二个解决方案吗?
【解决方案2】:

问题是您只调用“then”而没有再次设置变量。看下面的例子。

let arrdata = [1,2,3,4];
let prom = Promise.resolve();

arrdata.map(data => {

  // Here's the deal
  prom = prom.then(() => {
    console.log(data);
  });
});

prom.then(() => console.log('end'));

【讨论】:

    猜你喜欢
    • 2015-04-24
    • 2018-07-21
    • 1970-01-01
    • 2022-01-12
    • 1970-01-01
    • 2020-11-20
    • 1970-01-01
    • 1970-01-01
    • 2016-09-09
    相关资源
    最近更新 更多