0

I have a standard JavaScript project. It is mostly synchronous with a few callbacks. I needed to use a 3rd party library to simplify things. The issue is that this library is based on an async approach and Promises. I have never really used this approach before.

I have a situation where I just need something = get_info(); The code is all very modular, so there are multiple function calls stacked up. The problem is this get_info is async. I just can't figure out how to use this async function withing my project without having to rewrite the whole thing.

Edit: Here is an example of similar code

function my_class() {
    this.do_something( data ) {
        if ( this.get_data() == data ) {
            do_the_thing();
        }
    }

    this.get_data = function() {
        return library.get_info( arguments ); //can't do this, returns a promise
    }
}

var stuff = new my_class();

for ( var i = 0; i < len; i++ ) {
    stuff.do_something( i )
}

Again, the goal is to not rewrite this entire part of the application. Thoughts?

Nate
  • 21
  • 1
  • 7
  • 3
    without actual code, there's nothing to say except "learn how to use asynchronous code" – Jaromanda X Jun 25 '17 at 05:41
  • Yeah, that's kinda what I thought. This is a very in depth project. I'll try to simplify some code to give an example of what I'm talking about. – Nate Jun 25 '17 at 05:43
  • I added something that is similar to the situation, although much more simplified. – Nate Jun 25 '17 at 05:50
  • there are no (apparent) promises in the code you've posted, so how can you expect an answer on how to use promises correctly in your code? – Jaromanda X Jun 25 '17 at 05:51
  • @JaromandaX, if I knew how to do it, I wouldn't have asked. I appreciate your patience with me. The issue is that third_party_library.get_info( arguments ) is what returns the promise. I really need to just have the function return the value, but that doesn't seem possible. – Nate Jun 25 '17 at 05:53
  • Good. So now you've pointed out where the promise is. Until you did I could only guess. And that would not help you at all – Jaromanda X Jun 25 '17 at 05:58
  • Sorry about that, probably too many hours in front of a screen. Going on 14 hrs straight here :P – Nate Jun 25 '17 at 05:59
  • Just put `await` in front of the asynchronous call, `async` in front of the `function`, and treat the return value as a promise. –  Jun 26 '17 at 11:15

2 Answers2

0

There is no need to promisify every function that gets called in the chain. You can call either synchronous or asynchronous functions as much as you want within the chain of the promises. All you have to think about is where to wait for the resolved value.

Your code isn't far off from working, a simple addition of a .then() block makes it work.

Working example below:

function my_class() {
  this.do_something(data) {
    //Call the promise-returning function
    this.get_data()
      .then((resolvedData) => {
        //Wait for promise resolution
        //and compare the resolved value to 'data'
        if (resolvedData === data) {
          do_the_thing();
        }
      })
      .catch();
  }

  this.get_data = () => {
    return library.get_info(arguments);
  }
}

var stuff = new my_class();

for (var i = 0; i < len; i++) {
  stuff.do_something(i)
}

How does it work?

  1. do_something(i) is called
  2. this.get_data() is called from inside the do_something() function.
  3. When the promise that get_data() returns has been resolved, execution continues into then .then() block.
  4. The resolvedData is the resolved value from the get_data() promise.
  5. Compare the values, and continue.

As you can see, this does not take into consideration that the for-loop will continue even though the call to stuff.do_something(i) hasn't completed.

It is unclear in your question if you allow them all to run in parallel (like now) or if you need that they run in sequence.

If you want to to know if all calls are done, you can let do_something() return a promise and then wait for them all to resolve using Promise.all(), like below

function my_class() {
  this.do_something(data) {
    //Call the promise-returning function
    //Note that we return the same promise - no need to create a new one!
    return this.get_data()
      .then((resolvedData) => {
        //Wait for promise resolution
        //and compare the resolved value to 'data'
        if (resolvedData === data) {
          do_the_thing();
        }
      })
      .catch();
  }

  this.get_data = () => {
    return library.get_info(arguments);
  }
}

var stuff = new my_class();
//
var promises = [];
for (var i = 0; i < len; i++) {
  //Push each promise to the array
  promises.push(stuff.do_something(i));
}

Promise.all(promises)
  .then(() => {
    console.log("All promises have been resolved!")
  })
  .catch(() => {
    //Handle errors
  });
Daniel B
  • 8,770
  • 5
  • 43
  • 76
  • Have a look at the [this answer to another question](https://stackoverflow.com/a/34348311/1447173), and the [Promise documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) to better understand how it works. – Daniel B Jun 26 '17 at 11:09
-1

function my_class() {
    this.do_something( data ) {
          return new Promise(function(resolve,reject){
                this.get_data().then(function(dataReceiced){
                                    //reading promise retuned by    get_data();
              if(data == dataReceiced){
                  do_the_thing(); //need to promisify this also to use then();
                  resolve('Done');
              } else {   reject('Error'); }
                });  
           });
        }
    }

    this.get_data = function() {
        return library.get_info( arguments ); //can't do this, returns a promise
    }
}
i=0; // keep i global
var stuff = new my_class();

function doStuff(){
  if(i < len){ mainStuff(); }
}

function mainStuff(){
    stuff.do_something( i ).then(function(){
       i++; 
       doStuff();
    });

};
  doStuff(); // to start process. 

You need to promisify every function involved in the chain .. Something like this..

Not sure about the complete scenario , code will look something like this.

Atul Sharma
  • 9,397
  • 10
  • 38
  • 65
  • avoid the promise constructor anti-pattern. in `this.do_something` you don't need to wrap the call to `this.get_data()` in a promise constructor, when there is no need – Jaromanda X Jun 25 '17 at 06:59
  • @atulquest93 "You need to promisify every function involved in the chain" This was what I was dreading... I guess I was hoping there was another solution. Thanks for taking the time to help! – Nate Jun 25 '17 at 15:03
  • @Nate using async and sync in a same chain creates a lot of edge cases, be sure not to break the code. Best of luck – Atul Sharma Jun 26 '17 at 06:53