使用map和Javascript ES6 Promises

3

我正在尝试找到在map函数中等待所有数据获取完成并继续执行的最有效方法。我尝试使用'bluebird'库,并得出以下结论。

这是否有效,是否有更好的方法来实现这一点?

let urls = ['https://static.pexels.com/photos/36753/flower-purple-lical-blosso.jpg', 'https://static.pexels.com/photos/36764/marguerite-daisy-beautiful-beauty.jpg', 'https://static.pexels.com/photos/65609/tulip-tulips-sharpness-game-flower-65609.jpeg'];

let test = [];

Promise.map(urls, function(url) {
    // Promise.map awaits for returned promises as well.
    return getThumb(url);
}).then(function() {
    console.log(test);
});

function getThumb(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", url);
    xhr.onload = () => resolve(xhr.responseText);
    xhr.onerror = () => reject(xhr.statusText);
    xhr.send();
    test.push(url);
  });

https://jsfiddle.net/v80wmmsv/4/

非常感谢 :)

编辑:

以下是最终结果:

let urls = ['https://static.pexels.com/photos/36753/flower-purple-lical-blosso.jpg', 'https://static.pexels.com/photos/36764/marguerite-daisy-beautiful-beauty.jpg', 'https://static.pexels.com/photos/65609/tulip-tulips-sharpness-game-flower-65609.jpeg'];

Promise.map(urls, getThumb).then(function(data) {
  console.log(data.length);
}).catch(e => console.error(e));

function getThumb(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", url);
    xhr.onload = () => resolve(xhr.responseText);
    xhr.onerror = () => reject(xhr.statusText);
    xhr.send();
  });
};

你试过了吗?有什么问题吗? - Ruan Mendes
我不知道如何使用console.log来确保它是否正常工作。我只是在xhr结束时将函数参数推送到数组中,然后在map完成后记录该数组。我对这些异步的东西不太擅长。 - Jack M.
@JackM.:"我只是在 XHR 结束时将函数参数推送到数组的开头..." 为了明确起见,你是在 XHR 开始时推送它,而不是在它结束时。 - T.J. Crowder
2个回答

2

如果您想同时运行所有的promise,并在它们全部被解决时执行某些操作,您可以使用es2015 Promise.all()

let urls = ['https://static.pexels.com/photos/36753/flower-purple-lical-blosso.jpg', 'https://static.pexels.com/photos/36764/marguerite-daisy-beautiful-beauty.jpg', 'https://static.pexels.com/photos/65609/tulip-tulips-sharpness-game-flower-65609.jpeg'];

let test = [];

Promise.all(urls.map(getThumb)).then(function() {
    console.log(test);
});

function getThumb(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", url);
    xhr.onload = () => resolve(xhr.responseText);
    xhr.onerror = () => reject(xhr.statusText);
    xhr.send();
    test.push(url);
  });
};

1
而且呢?这也可以使用bluebird的Promise.map来完成,同样简洁,但是可以处理输入数组中的promise(在OP的代码中未使用),如问题所示。 - T.J. Crowder
2
@T.J.Crowder 为了少输入几个字符,却要增加另一个依赖? - marzelin
1
我并不是在推崇使用Bluebird。楼主正在使用Bluebird,问题也不是“如何在没有Bluebird的情况下完成这个任务?”(而且Bluebird不仅仅是为了节省几个字符那么简单。虽然我自己不用它,但我理解为什么有人会用。) - T.J. Crowder

1

以下是关于该代码的一些注释,这取决于您想要什么,可能会或可能不会成为问题:

  • test will end up with the URLs in the order in which they were requested (which I'm fairly sure is the same as their order in the original array, looking at the Promise.map documentation), not the order in which they were resolved (if you care)
  • test will contain the URLs even if they failed to load, since you're pushing them in the mapping function
  • You're resolving your individual promises with the text (well, image data) of the response, but not using that text anywhere
  • You're using an unnecessary wrapper function, no need for the wrapper around getThumb:

    Promise.map(urls, getThumb).then(function() {
        console.log(test);
    });
    

还有一个明显的问题:

  • 您没有处理失败:您需要使用catch(或使用第二个[失败]回调的then)。

除了缺乏错误处理之外,如果以上是您想要的,那么该代码就很好。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接