The "right" way to do synchronous HTTP request
Asked Answered
E

2

7

You probably came here to chide me but this is a real use case.

In the world of online education, there are SCORM courses. I have to make old SCORM courses work on a site. SCORM courses are "web based" and run in a browser, but they expect to run in an iframe and they expect the parent to supply a GetValue method and a SetValue.

So these SCORM courses are doing things like parent.SetValue("score", "90") and moving on. That function is supposed to return "false" if there was any issue.

SCORM comes from the 90's, and in modern web we know we have to do callbacks/promises and http fails "often". You might think the solution is a SetValue that writes to local data and then tries and retries until it get's through, but the SCORM course typically is set up to only move to the next screen if the SetValue worked, so you shouldn't be letting the user advance unless the SetValue actually was saved on the server.

TL;DR

Assuming a syncronous request is a requirement, what is the right way to do it?

So far I know of $.ajax({async:false ... but now browsers warn about that and sound like they're going to just ignore your request to be synchronous. I am thinking maybe using websockets or web workers or something is the right way to do a syncronous request in modern programming. But I don't know how to make a request like that. And I am not allowed change the code of the SCORM courses (they are generated with various course-making tools)

To clarify, I have full control over the implementation of the SetValue function.

Will $.ajax({async:false ... work long term? (5-10 years)

NOTE: it is entirely acceptable in this use case to completely freeze the UI until the request either succeeds or fails. That's what the courses assume.

Eveliaevelin answered 1/6, 2016 at 19:7 Comment(3)
I'm not sure I understand why you can't use async. You'd just use $.ajax().done(), you could do a modal popup that more or less freezes the background with a loading symbol or something.Leukocyte
@Leukocyte the SetValue function must actually return "true" or return false. I implement the function, but the SCORM course will call it, and the SCORM course will expect a true or false, not a promise.Eveliaevelin
I see, depending on how SetValue is called, you can do something like... var v = false; $.ajax(...).done(function() { v = true; }); function SetValue() { return v; }Leukocyte
H
5

So far I know of $.ajax({async:false… but now browsers warn about that

This is the right way (if you're using jQuery), it sends a synchronous XMLHttpRequest. Just ignore the warning. It's a warning that you are using outdated technology, which you already know.

and sound like they're going to just ignore your request to be synchronous.

That's unlikely.

I am thinking maybe using websockets or web workers or something is the right way to do a syncronous request in modern programming.

No, websockets and web workers are always asynchronous, you can't use them to make your asynchronous request look synchronous (in fact there's nothing that lets you do this).

Will $.ajax({async:false… work long term? (5-10 years)

We cannot know (and SO is not a crystal ball). It might, especially in older browsers, or it might not. Browser vendors are reluctant to break compatibility of features that run the web, and synchronous requests still are needed from time to time. At some point, too few (important) web pages will use it (<1%, <1‰, whatever threshold they decide on) and browsers will finally be confident to remove it. At that point, your business will have realised to deprecate these outdated course-making tools.

Hughey answered 1/6, 2016 at 19:30 Comment(5)
Thanks. To be clear, we don't "make" the courses. Other people give them to us to put on our site, and some were made 12 years ago. Regarding web workers, I was thinking something like a while(true) loop on the main thread and a web worker doing a request in the background or something.Eveliaevelin
@AwokeKnowing: I don't have any experience with SCORM, but I'm sure that the software generating these web pages will once be adapted to work asynchronously. Even if the SCORM standard will need to be adjusted for that.Hughey
@AwokeKnowing: Regarding web workers, no, that just won't work. The communication with the web worker is asynchronous, and you can't block the main thread waiting for an event by using a loop.Hughey
so actually SCORM is already a depricated standard, but it's excruciatingly wide-spread globally as it had US DoD backing and there are many thousands of SCORM courses that companies "bought" and will try to keep running for the next 20 years. I'm just trying to find a "modern" way to do a syncronous request, but if "there is none" then I accept that (it's reasonable).Eveliaevelin
@AwokeKnowing: I don't know whether the SCORM standard itself is deprecated of only the non-standardised parts of the particular implementation you are dealing with. And yes, there is no "modern way to do a synchronous request".Hughey
O
3

Based on my experience with learning management systems, the answer is: fake it.

You wrote:

it is entirely acceptable in this use case to completely freeze the UI until the request either succeeds or fails. That's what the courses assume.

Perhaps your courses assume this, but this is not the case in any learning management system I've used over the past decade.

From what I've seen, learning management systems don't use synchronous requests because they block other scripts, which gives the impression the page/course is locked up or broken. The workaround is to use async calls via an abstraction layer (which includes the SCORM API), and return 'true' to the course even if you have no way of verifying that the AJAX call was in fact was successful.

High-level view of how LMSs typically handle SCORM data:

When a course is launched, the LMS gets ALL of the course's existing SCORM data from the database, then puts it into a JavaScript object on the client side (accessible via the SCORM API). When you fetch data via SCORM, you are typically fetching data that is in this pre-loaded JS object -- you are NOT getting a real-time response directly from the database. Therefore AJAX is not needed when using SCORM's API.GetValue.

When you attempt to API.SetValue, you're initially storing the key/value pair in the JS object, not the SCORM database. Therefore the client-side JS object needs to synchronously indicate whether it successfully stored the data ('true') or not ('false'). The database -- and AJAX -- doesn't come into play until you try to persist the data to the database using API.Commit().

When you try to get a success value from API.Commit(), which is invoking AJAX, most LMSs will fake it. They will do an asynchronous request for the sake of ensuring the course doesn't feel broken, so the value returned from Commit() will almost always be 'true'. It's not reliable.

Obtain answered 1/6, 2016 at 21:41 Comment(2)
Yeah I admit that "entirely acceptable" is more of a sign of desperation rather than reason. I guess I'm trying to "blame" the standard for not considering the async/unreliable nature of the web. We actually currently are "faking it" but we are reporting to two different systems and when one request fails and the other succeeds, issues are showing up.Eveliaevelin
Doing sync on every call is going to make the UX horrible. Implementing a queue of AJAX messaging, or flagging a browser exit is going to help this a bit. But, for LMS systems that use a non-cached implementation and its making a round trip to the server on every get and set, plus forcing sync is probably the worst I've seen. Ultimately as Philip mentioned Commit is when it really should of been triggering this persistence of data, but it can also be cleaned up to not re-post unchanged data, or shrink it down to only what has changed vs the entire student attempt.Craniometer

© 2022 - 2024 — McMap. All rights reserved.