1

I have an array of strings let symbols = ['abc', 'cde', 'edf', 'qqe', 'hrt'] that I pass as an argument to the function:

async function fetchDetails(symbols) {
  let promises = symbols.map((s, i) => {
    return fetch(URL + s)
      .then(res => return res.json())
      .then(json => Object.assign({}, { [s]: json }))
  });
  console.log('promise:', promises)
  return Promise.all(promises);
}

I fetch data from URL/'abc', URL/'cde' etc. and save it into promises array.

But there is an % probability that from the server I will not get all 5 resolved objects. Then in console.log the promises array looks like this:

enter image description here

And I would like to have array containg only 4 resolved items (that I pass to the Promise.all(), instead of 5 (including 4 resolved and 1 with pending status).

If it was a synchronous function, I would simply have to have filtered the array. But I have no access to the [[PromiseStatus]] properties and have no idea how to do this.

Since I am quite new to the Javascript I would appreciate any help with this Async thing. Any scrap or code, or advise where to search for the answer :)

Edit: Maybe this will help a bit, the route I send a query to, is built like this:

app.get('/data/:symbol', async (req, res) => {
  const { params: { symbol } } = req
  const data = await stocks.getData(symbol, new Date())
  res.send(data)
})

So in the case of error, it doesn't send any error right? And that's why I could potentially have Pending Status instead of Reject?

SOLUTION OF THE TASK

Hey guys, so I solved this issue with 2 things: 1. Thanks to @Bergi, who pointed to the fact that Pending Status is not something that can be omitted - I checked server side and there was a first problem - Errors were not handled. 2. Then after fixing Server side, since I could separate Resolved Promises from Rejected - I was abble to return Array containing only Resolved promises - using this custom Promise_all solution: https://stackoverflow.com/a/46024590

So my final code looks something like this:

async function fetchDetails(symbols) {
  let promises = symbols.map(async (s, i) => {
    return await fetch(URL + s)
      .then((res)=> {
        if (!res.ok) {
          throw new Error('Error with fetch')
        } else {
          return res.json();
        }
      })
      .then(json => Object.assign({}, { [s]: json })) 
      .catch(err => {
        return Promise.reject()})    
  });

  const Promise_all = promises => {
    return new Promise((resolve, reject) => {
      const results = [];
      let count = 0;
      promises.forEach((promise, idx) => {
        promise
          .catch(err => {
            return err;
          })
          .then(valueOrError => {
            results[idx] = valueOrError;
            count += 1;
            if (count === promises.length) resolve(results);
          });
      });
    });
  }; 

  const results = await Promise_all(promises)
  const validResults = results.filter(result => result !== undefined);

  return validResults;
}

Thank you very much to everyone who was writing here!

5
  • Why does the promise keep pending? How will you know when to stop waiting? Commented Dec 8, 2017 at 12:55
  • Not sure if it will answer your question, but server simulates errors and there is a 5% chance that it will return an error instead of the data object - in this case, it is pending status (I guess). And when I have such situation I would like to bypass this promise and only store 4 resolved promises in the array. Commented Dec 8, 2017 at 13:06
  • 1
    Well no, if it returns an error status you should reject your promise to signal that error instead of leaving it pending. One needs to get notified of the error, otherwise we cannot distinguish the server having returned an error from the server not having returned anything yet. Commented Dec 8, 2017 at 13:11
  • how long would you like the timeout to be before failing the promise? Commented Dec 8, 2017 at 14:46
  • I Edited my post with some I guess useful information. Commented Dec 8, 2017 at 20:34

1 Answer 1

1

If you want to fail after a certain timeout you could do this:

const failIn = milliseconds =>
  setTimeout(
    _=>Promise.reject("timed out")
    ,milliseconds
  );

const Fail = function(details){this.details=details;};

const fetchDetails = symbols =>
  Promise.all(
    symbols.map((s, i) => {
      return Promise.race([
        fetch(URL + s),
        ,failIn(2000)//fail in 2 seconds
      ])
      .then(
        response=>[response,s],
        err = [new fail([err,URL+s]),s]
      )
    })
  )
  .then(
    responses =>
      responses.map(//map to json object from response or Fail type
        ([response,s]) => 
          (response && response.constructor === Fail)
            ? response
            : Object.assign({}, { [s]: response.json() })
      )
  );

The Fail objects are still included in the result, you could use filter to take them out if you're just going to ignore them:

  .then(
    responses =>
      responses.filter(
        ([response,s]) => (response && response.constructor !== Fail)
      )
      .map(
        ([response,s]) => 
          Object.assign({}, { [s]: response.json() })
      )
  )
Sign up to request clarification or add additional context in comments.

2 Comments

It might be easier to include a boolean in that result tuple than to wrap some values in that Fail thingy and others not.
@Bergi Yes, if you're ignoring rejected promises then you could do err =[false,s], noticed a bug in the reject handler as that one should return a tuple (fixing)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.