2

Before you all start screaming about refactoring and callbacks, read the question fully, please :)

I have the following situation in javascript (code simplified for convenience):

    function myFunc(){
        var myItems = getItemsAsync(); //this returns a promise

        return {
            settings: {
                type: "items",
                component: "accordion",
                items: myItems //WRONG! This is a promise, not the data itself!
            }
        }
    }

Here's the situation: I have an external framework that calls myFunc and expects the returned object {settings: etc...} to have all values already filled in, including the items sub-object. I have no control over how this framework calls myFunc, so I cannot change it to accept a promise or partial result, the returned object must be "ready" when myFunc returns.

Now, as you can see, here's the problem: to obtain the items I need to call an API that is asynchronous by design, and returns a promise. Unfortunately, this API is also out of my control, so I cannot modify it to work synchronously.

So basically I am at a stalemate: I have to synchronously return a complete object, but one of the pieces of that object can only be obtained asynchronously!!

Is there a way out of this? All the similar questions I've seen here on SO suggest that waiting for a promise to be complete cannot be done... is it true?

I know what you're all dying to say: "CHANGE EITHER THE CALLER OR THE API", but unfortunately they are both components that are totally out of my control, as they're part of existing systems that i CANNOT modify (due to bureaucratic, rather than technical, reasons)

Any ideas to get out of this?

Master_T
  • 7,232
  • 11
  • 72
  • 144
  • check this article https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests – MysterX Nov 14 '17 at 10:34
  • if myFunc has to return anything that is obtained asynchronously then it can not return a value synchronously - you will have to change how myFunc is called. There is no way to make asynchronous result synchronous ... just a moments thought and you'd realise why this is impossible – Jaromanda X Nov 14 '17 at 10:42
  • @JaromandaX : not even with polling/waiting? Sorry if this sounds silly, but I'm not an expert in javascript... why can't this be done? – Master_T Nov 14 '17 at 10:48
  • 1
    a function can't be "put on hold" while something polls or waits – Jaromanda X Nov 14 '17 at 10:49
  • @JaromandaX then I'm out of luck :/ thanks anyway – Master_T Nov 14 '17 at 11:02
  • Do you have any knowledge of when the properties of the returned `settings` object are accessed? So for ex when would `settings.items.` be called? – gotomanners Nov 14 '17 at 11:42

2 Answers2

3

Well, luckily for me I found out that the framework I mentioned in my question (the one that calls myFunc) has an initialization phase where I can inject as many promises as I want, and the framework will wait for them to complete before proceeding and calling the other stuff, including myFunc, so I was able to build my items object during this initialization phase and after that it was ready to be used.

This solves my problem, tho it doesn't answer my original question. I'll still wait a couple of days to see if someone knows of a workaround, but from what I've read in the meantime it appears what I want cannot be done.

Master_T
  • 7,232
  • 11
  • 72
  • 144
2

You know the answer already :-) If you have no other options, you have no options at all. It's fundamentally impossible to immediately return a value that will be obtained in the future.

That said, there exist some solutions that can halt the world of your caller, if you are able to wrap the entire framework in a Fiber or something similar. Of course that requires a fundamental change to the entire system, but can be done without changing the framework's code. This might cause some bugs due to unexpected timing, though.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Interesting, thanks for bringing Fiber to my attention, will come in handy if I find myself in a similar solution again. Luckily (see my answer) I was able to solve this in a "proper" way, but +1 to you for the info. – Master_T Nov 14 '17 at 13:32