【问题标题】:Do multiple .fetch() promises做多个 .fetch() 承诺
【发布时间】:2016-10-27 06:06:50
【问题描述】:

我想获取多张图片并将它们转换成 blob。我是一个关于承诺的新手,我尝试过但我无法通过。

下面是一个.fetch() 承诺

fetch('http://cors.io/?u=http://alistapart.com/d/_made/d/ALA350_appcache_300_960_472_81.jpg')
    .then(function(response) {
        return response.blob();
    })
    .then(function(myBlob) {
        var objectURL = URL.createObjectURL(myBlob);
        document.getElementById('myImage').src = objectURL;
    });

现在多个.fetch() 承诺(不工作)

var promises = [];

for (var i = values.length - 1; i >= 0; i--) {
    promises.push(fetch(values[i]));
}

Promise
    .all(promises)
    .then(function(response) {
        for (var i = response.length - 1; i >= 0; i--) {
            return response[i].blob();
        }
    })
    .then(function(blob) {
        console.log(blob.length); //undefined !!!
        for (var i = blob.length - 1; i >= 0; i--) {
            console.log(blob[i]);
            lcl_images[i].value = URL.createObjectURL(blob[i]);
            document.getElementById(lcl_images[i].id).src = objectURL;
        }
    })
    .catch(function(error) {
        console.log(error);
    });

【问题讨论】:

  • 那么.blob() 方法返回什么,blob 还是promise
  • .blob() 返回一个 blob(),但如果你正在做多个承诺,你必须在 .then(response) 中输入 return Promise.all(blobs)。在此之后,.then(blob) -> blob 是 blob 对象数组
  • 好的,所以如果.blob() 是同步的,那么你不需要两个.then。 Promise.all(promises).then(function(responses) {...}).catch(...);将完成这项工作,而无需创建 blob 数组。
  • 如果你自己试试这行不通,我是一个关于承诺的新手。我已经按照你说的做了几次尝试,但你必须返回承诺 response[i].blob() 并且在下一个 .then 你将拥有 blob 对象。
  • 我会为你写一个答案。

标签: javascript promise blob fetch


【解决方案1】:

一般规则是,promise 链成功路径中的完全同步中间步骤可以与下一步合并,允许从链中省略一个 then()

该语句实际上有一个附带条件,涉及中间捕获,但对于这个答案就足够了。

因此,如果.blob() 方法是真正同步的(它返回一个值),则只需要一个.then(),而不是两个。

这里有两种方法,都可以利用Array.prototype.map(),并且都应该有效(尽管它们在错误条件下会有所不同):

1.简单的.map(),详细信息在Promise.all()

var promises = values.reverse().map(fetch); // you may need .reverse(), maybe not. I'm not 100% sure.

return Promise.all(promises).then(function(responses) {
    responses.forEach(function(r, i) {
        var imageObj = lcl_images[i],
            element = document.getElementById(imageObj.id);
        imageObj.value = URL.createObjectURL(r.blob());
        if(element) { //safety
            element.src = imageObj.value;
        }
    });
    return responses; // here, return whatever you want to be made available to the caller.
}).catch(function(error) {
    console.log(error);
});

如果你愿意,你可以写:

return Promise.all(values.reverse().map(fetch)).then(function(responses) {
    // ...
});

2。 .map() 中的详细信息遵循简单的Promise.all()

var promises = values.reverse().map(function(val, i) {
    return fetch(val).then(function(result) {
        var imageObj = lcl_images[i],
            element = document.getElementById(imageObj.id);
        imageObj.value = URL.createObjectURL(result.blob());
        if(element) { //safety
            element.src = imageObj.value;
        }
        return result; // here, return whatever you want to be made available to the caller.
    });
});

return Promise.all(promises).catch(function(error) { // return a promise to the caller
    console.log(error);
}); 

注意事项:

  • 如果任何一个fetch() 失败,(1) 将完全失败。
  • (2) 将为所有 成功 提取执行所有 imageObj.value ...element.src = ... 内容,即使一个或多个 fetch()... 失败。任何单一的失败都会导致Promise.all(promises) 返回一个被拒绝的承诺。
  • (1) 或 (2) 可能更合适,具体取决于您的需求。
  • 还有其他错误处理可能性。
  • 如果这两种方法都不起作用,那么最合理的解释是.blob() 方法返回的是一个承诺,而不是一个值。

【讨论】:

  • 如果这是被调用的 API,那么它很酷。除了 promise 之外的任何对象都可以。
【解决方案2】:

您在第一次响应后从 then 处理程序返回,而不是您需要做的是返回 blob 列表:

Promise
.all(promises)
.then(function(response) {
    // CHANGED HERE
    var blobPromises = [];
    for (var i = response.length - 1; i >= 0; i--) {
        blobPromises.push(response[i].blob());
    }
    return Promise.all(blobPromises);
})
.then(function(blob) {
    console.log(blob.length);
    for (var i = blob.length - 1; i >= 0; i--) {
        lcl_images[i].value = URL.createObjectURL(blob[i]);
        document.getElementById(lcl_images[i].id).src = objectURL;
    }
})
.catch(function(error) {
    console.log(error);
});

【讨论】:

  • 我已经编辑了你的解决方案并添加了console.log(),你可以清楚地看到问题:我在blob promise中没有blob对象,这就是它引发错误的原因:@ 987654322@
  • 当你 return blobs 时,你会在下一个函数中得到 blobs,而不是 blobblob.length 未定义,因为它是一个 blob 数组,而不是单个 blob。
  • 同样在这种情况下,您的 blobs 实际上是一个 promises 数组,这意味着您需要 return Promise.all(blobs)。真的,您应该将 blobs 重命名为 blobPromises 或其他名称。
猜你喜欢
  • 2016-10-28
  • 1970-01-01
  • 2017-02-08
  • 2021-01-28
  • 2022-06-12
  • 2017-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多