简体   繁体   中英

How to synchronously call multiple times any function which is returning promise

For example, I have function which Promise.resolve() if I already have any cached entity id else it make ajax call to reserve entity id and then Promise.resolve() new entity id

function getReservedEntityId(collectionName) {
        //if (!haveCachedIds) {
            //make ajax call to reserve new ids
            Promise.resolve(newId);
        }
        return Promise.resolve(cachedId);
};

How can we synchronously call it multiple times to reserve multiple entity ids?

PS I know that the correct approach is to make this function take parameter that will specify the count of entity ids and make request and return ids accordingly but I wanted to understand how can we call synchronously multiple times any function which is returning promise.

First, the implementation of getReservedEntityId() needs to make correct use of promises. I recommend a thorough reading of how promises work . In particular, it's important to understand that when your function performs an asynchronous task, you need to return a promise that will either resolve or reject based on the result of the asynchronous task.

function getReservedEntityId(collectionName) {
  if (haveCachedIds) {
    return Promise.resolve(cachedId);
  } else {
    return new Promise((resolve, reject) => {
      // Make the AJAX call and call resolve(newId) in the success callback
      // or call reject(errCode) in the failure callback.
      // The arguments newId and errCode can be any values you like and are
      // the values that get passed to the next link in the promise chain
      //   i.e. the values passed to then() or catch()
    });
  }
}

With that squared away, there are two recommended ways to make the calls synchronous:

1) Utilize a promise chain

getReservedEntityId(collectionName)
  .then((id) => {
    // Probably want to do something with `id` first...

    return getReservedEntityId(collectionName);
  })
  .then( ... )
  .then( ... );

Of course, if you're going to pass the same function to each .then() call, you could just as well declare it as a regular function so as to not repeat yourself.

2) Using async/await

This is a new ES2017 feature and is still not widely supported. As of the time of this writing, Node.js supports async/await with the --harmony flag, but most browsers do not . That said, async/await is intended for this exact purpose, treating functions returning promises as though they were synchronous. If you want to start using async/await in your code now, it is common practice to use JavaScript transpilers which which transpile your future-ready JavaScript to code that is supported by all major browsers.

This is how you would use async/await:

(async function someAsyncFunction {
  const id1 = await getReservedEntityId(collectionName);
  const id2 = await getReservedEntityId(collectionName);
  const id3 = await getReservedEntityId(collectionName);
                          .
                          .
                          .
})();

The syntax is much nicer and more readable than the promise chain because it's designed for this exact purpose. Note that I have made the function self-invoking here so that it matches your behavior without having to make an extra function call. But you can use and call a function defined with async function just like any other function that returns a promise.

@fvgs your answer is also correct. But here's the complete solution and the challenge which I have faced is to maintain list of reserveIds which was in response of every getReservedEntityId call.

getEntityIds: function (entity, count) {
    if (!count || count == 1)
        return Utils.getReservedEntityId(entity);

    var promise = new Promise(function(resolve, reject) {
        var result = [];
        var chain = Utils.getReservedEntityId(entity);
        var callBack = function CB (result, newId) {
            result.push(newId);

            if (result.length == count)
                resolve(result);
            else
                return Utils.getReservedEntityId(entity);
        }.bind(null, result);

        for (var i=1; i <= count; i++) {
            chain.then(callBack);
        }

        chain.catch(reject);
    });

    return promise;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM