0

I have a low level common function which is the bottom of the call tree in many places.

There is an async transaction, and I want to block until the async request completes, before returning.

I could use await. E.g await admin.database().ref(url).update(value);.

But, if I use await then I must mark the function as async. Which means that must mark all of its callers as async, and all of theirs, all the way up to the top.

Would it be evil of me to code my blocking function like this?

Perhaps I am missing something?

/**
 * Perform a blocking write to the database. It is the responsibility of the caller to catch any exceptions.
 * 
 * @param {string} url - the URL of the node to be updated.
 * @param {string | Object} value - the value to be written
 */
expors.updateDatabase = function(url, value){
    admin.database().ref(url).update(value).then(() => {
        return;
      });
}

This might sound opinion-based, and I won't deny that I would be happy to hear about industry standard best practise, but what I am really after is whether there is any technical reason not to do this.

halfer
  • 19,824
  • 17
  • 99
  • 186
Mawg says reinstate Monica
  • 38,334
  • 103
  • 306
  • 551
  • The code you posted will just synchronously return `undefined` without waiting for the db update to finish. I'm not even sure it's possible to synchronously wait for that promise to finish without modifying how js handles its event loop. For better or worse, in js, _any function which relies on an asynchronous process must itself be asynchronous._ – CRice May 27 '22 at 18:52
  • If you are in nodejs you might be able to use a package, per [the answers to this question](https://stackoverflow.com/questions/46273583/how-make-promise-execute-synchronously). However it is noted that it won't work in the browser. – CRice May 27 '22 at 18:55
  • 2
    _Why_ do you need to wait for this function in the first place? And how are you planning to make it blocking? Blocking functions are bad practice in the least, especially for browsers. There is a good reason why many browsers have deprecated the [`XMLHttpRequest.open()` `async` parameter](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/open#parameters). – Ivar May 27 '22 at 19:04
  • It makes an HTML request to Firebase. I want to block until the value has been read from the database before continuing, as I need its value. Isn't `promise.then` equivalent to `await`, and don't hey both block? – Mawg says reinstate Monica May 27 '22 at 19:45
  • 1
    Nope, not possible. – Jonas Wilms May 27 '22 at 20:39
  • But it would be ok if I unroll that inner transaction? I am still unsure how complex transactions can be. Is there a limit? – Mawg says reinstate Monica May 27 '22 at 21:01
  • @CRice can you help me by explaining why you say `The code you posted will just synchronously return undefined `? I can see that it would if I didn't `promise.then` and just `promise`; but surely that `promise.then` in the function blocks until the promise resolves? – Mawg says reinstate Monica May 27 '22 at 21:07
  • 1
    @Mawg, no that's not how Promises work. (Or callbacks in general.) It's one of the examples in the duplicate and is explained there pretty well. Getting familiar with [the Event Loop](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#event_loop) might also help you understand why what you want is not possible. – Ivar May 27 '22 at 21:12
  • I can see that I am going to have to do more reading. I am family with callbacks for decades, in the embedded world, but am relatively new to JS. As I understand it, `async` is sugar coating to wrap a `promise`, which itself just wraps a callback. As some point, the ascn event has to complete and the value become available. I grok how that happens with callbacks. I though that that `pronise.then` meant resolve the promise and then, when the value has been read, do the code in the `.then`. And I thought that was the same as `await`. Both seem to be blocking to me – Mawg says reinstate Monica May 27 '22 at 21:19
  • Again, I know that a promise is not blocking, but I thought that the `.then` clause waited for it to resolve, which is, to my mind, blocking. Thanks very much for your help – Mawg says reinstate Monica May 27 '22 at 21:20
  • 1
    Promises are just a construct to manage callbacks. The `.then()` callback is invoked when the Promise resolves, so in that sense it is "blocking", but that only applies to the callback passed to the `.then()`. The surrounding `updateDatabase()` function doesn't wait with returning for that. In fact (as explained in the link about the event loop) JavaScript has the concept of "run to completion" so all the code in the current event-loop cycle need to be finished before the `.then()` callback will be executed. – Ivar May 27 '22 at 21:24
  • Ah, some light begins to dawn. I played about with AngularJs a few years back, and that has a "digest cycle" that sounds like it was the "event loop". So, the code that calls my `updateDatabase()` function continues to run until it returns, and sometime later the database read gets resolved in `updateDatabase()`? But, if the calling function uses the database read result, I get confused. Since my `updateDatabase()` has a `.then`, does that resolve the promise? I thought that it did. But I can see from your event loop explanation that it will continue to run ... – Mawg says reinstate Monica May 27 '22 at 21:34
  • ... as will code in the caller, after the point where it called `updateDatabase()` and it will try to to access the data returned by that db fn, which will initially be undefined ? – Mawg says reinstate Monica May 27 '22 at 21:34
  • "_But, if the calling function uses the database read result_" It can't, that's the problem. With the `.then()` you essentially say "Here you have a function, please invoke it when you're ready, I continue in the mean time." The `return` you have inside the `then()` is only part of the callback (arrow) function. The `updateDatabase` function itself doesn't have any `return` and as such implicitly returns `undefined`. That is why Promises are useful, because you can pass a Promise back which will resolve once it has been completed and that way you can manage the asynchronous flow. – Ivar May 27 '22 at 21:48
  • And that's where `async` and `await` come in. Because that is indeed syntactic sugar for Promises. `async` functions implicitly return a `Promise` and everything after an `await` is essentially what otherwise would've been inside of the `.then()` callback. – Ivar May 27 '22 at 21:49
  • Aha!! I knew that I had a blind-spot. And I think that I have finally resolved it with your help (or am getting very close to doing so). Let's say that A calls B, calls C, calls `updateDatabase()` and B needs the data read from the DB. I have to make `updateDatabase()` async, and everything that calls it, up the tree until the await in B? So, B and C are also aync, and B awaits C which awaits `updateDatabase()`? – Mawg says reinstate Monica May 27 '22 at 22:00
  • Or, if I use promises (which is less preferable), then I ought to pass a promise back up the call tree and `.then` it at the point that I need the Data (in B)? E.g. I need to move my `.then` from `updateDatabase()` to B, and C just returns the promise returned to it by `updateDatabase()`? – Mawg says reinstate Monica May 27 '22 at 22:01
  • @MawgsaysreinstateMonica Yep, indeed. :) – Ivar May 27 '22 at 22:02
  • Btw, If you can clarify it, I will award a bounty of 200 points, or create a new question to award them. Thank you for your patience so far. – Mawg says reinstate Monica May 27 '22 at 22:02
  • Aha! Thanks a 1,000,000. I will post a new question, link it here, you can just post "yes" as an answer, and in 2 days when I am allowed to award a bounty, I will do so. Plain old callbacks are bread & butter to embedded programmers, but I seem to have had a blindspot with promise & async (C++ 14 added promises, but we tend not to use them) – Mawg says reinstate Monica May 27 '22 at 22:05
  • 2
    It's all good. There is plenty on this on SO already, so I don't think another one is going to be very useful. But I appreciate the gesture. – Ivar May 27 '22 at 22:07
  • 1
    Wow! Thanks, Ivar. Sure, there's plenty, but I read many and never got it clear until now :-) I see that you are in Holland. I worked a great year in Enschede once. Also, I had a good friend called Ivar when I worked in Norway:-) – Mawg says reinstate Monica May 27 '22 at 22:14
  • Sorry to be cheeky, but I have on last question. A is not intersexed in the data, but calls B, which is. DOEs A have to be `async` and to `await b()`? Or is it just a plain old function, with a plain old function call? Thinking about it in terms of call backs & the even loop, I believe that it is just plain old ... – Mawg says reinstate Monica May 28 '22 at 06:45

0 Answers0