Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Promise.all not working as expected

I am having trouble writing an asynchronous function using promises

function requestsPlot(plot, info) {
  return new Promise(function(resolve, reject) {
    var plotObject = fieldsObject[plot]
    var sqr = new Promise(function(resolve1, reject) {
      debugger;
      get(createSQRurl(plotObject.polygon))
        .then(function(result) {
          plotObject.quality = sqrHtmlParsing(result);
          resolve1();
        });
    });
    var soilType = new Promise(function(resolve2, reject) {
      get(createSoilTypeUrl(plotObject.polygon))
        .then(function(result) {
          plotObject.soilType = soilTypeHtmlParsing(result);
          resolve2();
        });
    });
    var distance = new Promise(function(resolve3, reject) {
      var start = turf.centerOfMass(plotObject.polygon).geometry.coordinates;
      var end = info.homeCoords;
      get('http://router.project-osrm.org/route/v1/driving/' + start + ';' + end + '?overview=false')
        .then(function(result) {
          var parsed = JSON.parse(result);
          if (parsed.code == 'Ok') {
            plotObject.distance = parsed.routes[0].distance / 1000;
            resolve3()
          } else {
            plotObject.distance = '';
            resolve3()
          }
        });
    });

    Promise.all([sqr, soilType, distance]).then(function() {
      resolve('test');
    })
  })
}

The idea is to resolve the promise returned by the requestPlot function after all promises inside the function (variables sqr, soilType and distance) are resolved. However, the promise is resolved while all requests in the get function are still pending. Note that the 'get' function also returns a promise. Thanks a lot for your help!

P.S. here's the get function

function get(url) {
  var requestPromise = new Promise(function(resolve, reject) {
    var req = new XMLHttpRequest();
    req.open('get', url);

    req.onload = function() {
      if (req.status == 200) {
        resolve(req.response);
      }
      else {
        reject(Error(req.statusText));
      }
    };

    req.onerror = function() {
      reject(Error("Network Error"));
    };
    req.send();
  });
    return requestPromise
}
like image 864
Christoph Pahmeyer Avatar asked Jul 18 '17 21:07

Christoph Pahmeyer


People also ask

What if one promise fails in promise all?

Promise.all is rejected if any of the elements are rejected. For example, if you pass in four promises that resolve after a timeout and one promise that rejects immediately, then Promise.all will reject immediately.

Does promise all maintain order?

Here, Promise. all() method is the order of the maintained promises. The first promise in the array will get resolved to the first element of the output array, the second promise will be a second element in the output array and so on.

Does promise all throw error?

As we can see in the output above, even though the promise2 function throws an error, the Promise. all() method does not get rejected, and the browser throws an unhandled error.

What happens if a promise does not resolve?

So failing to resolve or reject a promise just fails to ever change the state from "pending" to anything else. This doesn't cause any fundamental problem in Javascript because a promise is just a regular Javascript object.


2 Answers

Nesting promises within promises is a well-known anti-pattern.

You don't need any of those promise constructors because you already have get which returns a promise and you can just use it directly.

Here's how you can re-write your code:

function requestsPlot(plot, info) {

  const sqr = get(createSQRurl(plotObject.polygon))
    .then(sqrHtmlParsing);

  const soilType = get(createSoilTypeUrl(plotObject.polygon))
    .then(soilTypeHtmlParsing);

  const start = turf.centerOfMass(plotObject.polygon).geometry.coordinates;
  const end = info.homeCoords;
  const distance = get('http://router.project-osrm.org/route/v1/driving/' + start + ';' + end + '?overview=false')
    .then(JSON.parse);

  return Promise.all([sqr, soilType, distance])
    .then(([parsedSqr, parsedSoilType, parsedDistance]) => 
      Object.assign(plotObject, {
        quality: parsedSqr,
        soilType: parsedSoilType,
        distance: parsedDistance.code == 'Ok'
          ? parsed.routes[0].distance / 1000
          : ''
      }))
}
like image 167
nem035 Avatar answered Oct 28 '22 10:10

nem035


In modern javascript with async/await syntax , the promise.all syntax should look like this

await promise.all([asyncfuntion1(),asyncfunction2(),...])

Dont forget to call your asynchronous functions in the promise list -> asyncfunction1() not just asyncfuntion1

like image 1
yahya benzha Avatar answered Oct 28 '22 09:10

yahya benzha