2

I'm required to make two API calls simultaneously. And one of the callback has to be executed before the other. But making the calls sequential is slow and bad for user experience:

axios.get("/get_some_data").then(function(resp) {
    do_some_operation();

    axios.get("/get_other_data").then(function(resp) {
            do_other_operation(); // Needs /get_some_data and /get_other_data both be done
        });
    });
});

Making parallel calls and wait for another can be done easily in C++ using std::conditional_variable with the following pseudo (C++17 ish) code

std::conditional_variable cv;
std::mutex mtx;

get_request("/get_some_data",[&](auto&& resp){
    do_some_operation();
    
    // Notify that the operation is complete. The other callback can proceed
    cv.notify_all();
});

get_request("/get_other_data",[&](auto&& resp){
    // Wait until someone notify the previous task is done
    std::lock_guard lk(mtx);
    cv.wait(lk);

    do_other_operation();
});

I've searched on various websites. But I don't think JavaScript comes with anything like std::conditional_variable or even a std::mutex. How could I make parallel requests but make a callback wait for another?

Mary Chang
  • 865
  • 6
  • 25
  • 2
    [Promise all....](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all) – epascarello Oct 26 '20 at 02:33
  • 1
    `Needs /get_some_data and /get_other_data both be done` at that point, they WILL both be done - of course, you can't access `/get_some_data` response, because BOTH your responses are called `resp` ... try renaming one of those – Jaromanda X Oct 26 '20 at 02:34
  • That's fine. I'm showing pseudo code and there's a way I could reference the object I need. To be clear, I want `do_some_operation` run as soon as it can but `do_other_operation` should wait. – Mary Chang Oct 26 '20 at 02:37
  • _"sanctimoniously"_ Did you mean concurrently? Sequentially? Could you perhaps describe using plain language what you want to happen and more importantly, when? – Phil Oct 26 '20 at 02:38
  • Also, if both API responses got back at the same time. `do_some_operation` should run first – Mary Chang Oct 26 '20 at 02:38
  • Thanks, I messed the bad auto-correct. simultaneously – Mary Chang Oct 26 '20 at 02:40
  • Does `/get_other_data` or `do_other_operation()` depend at all on `/get_some_data` or `do_some_operation()` completing? Even though you've corrected your typo, it would still really help if you spelled out the desired sequence – Phil Oct 26 '20 at 02:43
  • Your C++ code is also sequential and also the same slowness as the javascript code because it blocks at the mutex. Both are the same slowness – slebetman Oct 26 '20 at 03:38
  • Wait, I'm a bit confused. In your C++ does `get_request` fetch the request or does `do_some_task` fetch the request? My previous comment assume `do_some_task` fetches the request – slebetman Oct 26 '20 at 03:40
  • `get_request` sends a HTTP GET to some endpoint and calls the lambda. I should make the lambda accept parameters. Well.. pseudo code. Updating – Mary Chang Oct 26 '20 at 03:42
  • Also removed the first lock. It is unnecessary. – Mary Chang Oct 26 '20 at 03:44

2 Answers2

2

Sounds like you want something like this

const some = axios.get("/get_some_data").then(res => {
  do_some_operation()
  return res
})
const other = axios.get("/get_other_data")

Promise.all([some, other]).then(([ someRes, otherRes ]) => {
  do_other_operation()
})

This will call both URLs in parallel.

When the first resolves, it will call do_some_operation(). This (presumably) synchronous operation becomes part of the some promise resolution. The other promise resolves once the HTTP request completes.

Once both some and other promises are resolved, call do_other_operation()

Phil
  • 157,677
  • 23
  • 242
  • 245
  • Is `some` returning a promise here? – IvanD Oct 26 '20 at 03:02
  • 1
    @IvanD `some` **is** a promise. I'm not sure what you mean by _returning_. `.then()` always returns a new promise – Phil Oct 26 '20 at 03:04
  • If you downvote, could you please leave a comment explaining why? – Phil Oct 26 '20 at 03:15
  • OK, because I do not see any problem with your code, except it is a little bit less readable. I prefer to use Promise.all for more than 2 or dynamic number of promises to wait for. – IvanD Oct 26 '20 at 03:28
  • Speaking of the `some` being a promise itself, I rarely use `.then`, so I forgot that it returns a promise itself. Thanks! – IvanD Oct 26 '20 at 03:29
  • I typically use `async` / `await` too but I also try and match the style used in the question itself. – Phil Oct 26 '20 at 03:31
1

Use promise all

Promise.all([
  get_request("/get_some_data"),
  get_request("/get_other_data")
]).then( function(responses) {
  console.log(responses);
  // do what you want
  do_some_operation();
  do_other_operation();
}).catch(function(error) { 
  console.error(error.message);
});

OR

Promise.all([
  get_request("/get_some_data").then(function (resp) {
    do_some_operation();
    return resp;
  },
  get_request("/get_other_data")
]).then( function(responses) {
  console.log(responses);
  // do what you want
  do_other_operation();
}).catch(function(error) { 
  console.error(error.message);
});
epascarello
  • 204,599
  • 20
  • 195
  • 236
  • I think (and could be totally wrong about this), that one of the main things OP wants to do is call `do_some_operation()` as early as possible without waiting for the second request to resolve – Phil Oct 26 '20 at 03:24
  • Yeah, but that's not as early as possible. That would still be waiting for both requests to complete – Phil Oct 26 '20 at 03:27