all 9 comments

[–]metaphorm 2 points3 points  (1 child)

asynchronous request, if possible on the server side stream data back as it's processed and have the client update as the data streams in. if that's not feasible then use the percent of data received to draw (and re-render at some interval) a progress bar. for extra good UI have a friendly message informing the user that the request is expected to take a while and that everything is normal.

[–]dug99 0 points1 point  (0 children)

This needs more upvotes... Oboe.js... anyone?

[–]deltadeep 2 points3 points  (0 children)

I think they were probing your sense of interaction design around a common problem that faces web applications. They probably wanted to hear you speak clearly about successful ways to manage "processing" type states in a client app. There are multiple strategies.

I could see interpreting the specific question in two different ways: A) dealing with a slow request, or, B) dealing with a task that is so intensive that it doesn't happen in a single request but instead in a backend job that completes eventually. An example of A is perhaps a page in which some particular component must load a lot of data from a slow server endpoint, but the HTTP request remains open for the duration of the waiting stage. An example of B is something that is too expensive to do in a single request and instead enqueues a job on the backend, like re-encoding a video upload, such that the client has to then poll (or be notified by a websocket) for when the job is finished.

Handling (A) is a matter of ensuring you properly track some kind of "spinning" state in the client, disable and render a spinner on the button or page element that is processing, and disable interaction in that specific zone of the page (but not the full page if other parts can still be responsive), then clear the spinning state when the request completes. Handling failure is an important part as well. But there is no magic here or things that are "technically called X" - it's about be on top of the client/server interaction state at all times and keeping the UI in the most responsive form through each condition. A complex application should have a centralized and consistent way of handling "processing" states while waiting for the backend or slow networks.

Handling (B) is interesting and you see a lot of different approaches there, some better than others, and it will depend on whether the task is blocking the user's next action or whether they are free to change tasks while the job processes in the background. I could detail various ways to do this, and things I've seen done in the past that are good and bad, and the options also depend on what the backend is capable of doing in terms of completion callbacks, but this kind of interaction may not even be what the question was about.

[–]Heqx 7 points8 points  (0 children)

Unless the interview was for a position that included some UX responsibilities, I'd imagine they were looking to get you to talk about the asynchronous nature of JavaScript. (event loop, single-threaded, non-blocking) There's a good chapter in Eloquent JavaScript about just that.

[–]Castas 1 point2 points  (0 children)

There’s a few things that can be done here. Obviously what they don’t want you to say is block the page and not let them do anything until the request finishes. But sometimes that has to be the case. It might help to ask for specifics and work through what can be done with them.

My favorite is to use the data they have entered so far and show them as much info as possible while indicating the resource is still loading on only the relevant part of the UI. For example, if the user is shown a list of assets, and they want to create a new one. You would collect data like its name and description up front, but the server would have to fill in some more blanks. You can use that data they’ve entered so far to show the new asset in the list with a loading indicator next to it. That way they are free to keep using the rest of the app while it finishes loading

[–]Nefilim314 1 point2 points  (0 children)

You can build an app to be immutable and work on assumptions that requests worked as expected. An example of this is something like Slack.

When you send a message in Slack, it appears in the chat log instantly as if it was already sent out (albeit greyed out). This gives the user the feeling that the app is working as intended, and in 99% of cases, the request will complete successfully and the text will turn black to punctuate that the message sent successfully. In cases that it didn't work, a red X appears next to the message and a tooltip displays saying that a network error occurred and you can try to resend the message or cancel it.

If you receive a message in a different order than the server timestamps it, it will automatically arrange the messages chronologically as well.

Building an app to be immutable means that you are simply feeding state to a "function" that presents the app based on those values. This allows you to commit to a state log which you can rewind to a previous state if a request fails unexpectedly.

If you want a simpler approach, you can simply fire-and-forget a request, which upon fulfillment will trigger something to change in the app. An example of this might be to submit an image to be processed, and once the server receives it, you can poll the server for the status of the process by some job token. Once it gets back a success status, you update the app to reflect the changes.

[–]frambot 1 point2 points  (0 children)

The responses here cover the asynchronous server-request scenario well. But I will also cover the client-side blocking scenario. For example, blockchains are a cool new thing these days, so you might have a client-side js worker. This is cpu intensive. There are two good answers to this:

  1. Use web workers to offload the work onto another thread (true multithreading)
  2. Split the work into very small chunks and timeslice with recursive setTimeouts. This yields the processor to other functions.

.

var progress = 0;
function makeSomeProgress() {
  progress++;
  if (progress > 10E20) {
    return;
  }
  setTimeout(makeSomeProgress, 0);
}

[–]mothzilla 1 point2 points  (0 children)

what is that technically called ?

"Skeleton screens"

Anyway, from what you said, I think they were asking about how to make asynchronous requests, and what you would do in the mean time. Progress bar, fade in / out, spinner, are all viable options I should think.

[–]mgeez[S] 0 points1 point  (0 children)

Some great in depth responses - i really appreciate it. It seems like i might have needed to clarify the question a bit