Jack M.
Jack M.

Reputation: 2031

Javascript ES6 Promises with map

I'm trying to figure out the most efficient way to wait inside map function until all datas are fetched and then continue. I tried with the 'bluebird' library and came out with this.

Is this even working right and is there even better way to achieve this?

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/

Thanks :)

Edit:

This is the final outcome:

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();
  });
};

Upvotes: 3

Views: 7234

Answers (2)

T.J. Crowder
T.J. Crowder

Reputation: 1075635

Some notes about that code, which may or may not be issues depending on what you want:

  • 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);
    });
    

And one definite issue:

  • You're not handling failure: You need a catch (or a then with the second [failure] callback).

Other than the lack of error handling, if the above is what you want, that code is fine.

Upvotes: 1

marzelin
marzelin

Reputation: 11610

If you want to concurrently run all promises and do something when all of them are resolved, you can use 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);
  });
};

Upvotes: 2

Related Questions