Trying to understand the view-update loop better

Hi,

I’m trying to achieve something that should be pretty simple (on the face of it), but it has highlighted my lack of knowledge of the view-update loop in respect to DOM re-draws, and so was hoping someone could enlighten me.

(I may also be suffering from a mind-blockage and simply missing the 'bleedin obvious` :smile:)

My Scenario

I am retrieving a heap of data from my server that takes a few seconds to be processed by Elm when it is received. I therefore want to provide information to the user of the current state - Loading then Processing then Ready.

My Problem

When the data is received, I can switch the state on the model from Loading to Processing, and begin processing the data, but the update to the model state is not reflected in the view until the processing is complete. This I understand and expected.

Solutions?

I guess I need to trigger a re-draw of the DOM? I thought the following might suffice:

  1. When the data is received in update:
    a. update the model state: { model | state = Processing }
    b. start a Task: Task.perform TimeMsg Time.now
  2. When TimeMsg is received in update start processing the data

I figured the view would be updated between steps 1 and 2 and reflect the new model, but it appears that it isn’t.

I could try various other Tasks, and maybe try ports to force the view-update loop to be triggered with the updated model, but I feel that I don’t really understand the cycle, and although I might find a solution I would prefer to understand it rather than simply find it by experimenting and maybe end up with the wrong assumptions.

Also, using a built-in Task or a port loop feels a bit hacky, and doesn’t really express that all I want to do is to update the view prior to starting to process the data received in update.

Can someone explain further or point me to some reading? I would like to understand more about what is going on under the hood. (Do some Tasks, but not others, cause the view-update loop to be initiated with the updated model, if so, how do you determine which ones? Is there a way to create a custom Task that expresses better what I want to achieve - assuming this forces a DOM re-draw.)

TIA to anyone that can explain further.

There are two update loops. The first one is the one that updates the model and the second one is the one that updates the DOM.

The first loop is capable of handling a high frequency of updates. The second one is bound to the animationFrame. This means no more than 60 updates per second.

In your case, most likely, the arrival of the data and the processing of the data happen on the same frame and this is why you are not seeing “Processing”. The call to Time.now returns too fast to matter. So, I would expect that if you use Process.sleep 20 |> Task.perform (\_ -> StartProcessing) , you should be able to see the change in the model.

1 Like

Thanks.

I’ve just this minute used a subscription to Time.every 100 StartProcessing which works, but hides the logic behind an if in subscriptions - your solution is more of what I was looking for, and your explanation clears up a few things for me. :+1:

To complement this, JavaScript is single threaded, so the next frame has to wait for any computation started before it was scheduled. That is why pages sometimes feel unresponsive. If you want to be really sure that the view was updated, you can wait for message from onAnimationFrame before starting computation, or run it in a different web worker.

You might also be interested in those discussions:

1 Like

The processing is of data requested by the user, so if it makes the page unresponsive for a couple of seconds that’s acceptable in this case, they will be expecting a slight delay. The data is coming in over a WebSocket, so if it does become too large and slow to process I could push it from the server in chunks, and process it incrementally with feedback.

Thanks for the info, and the links (including the one to my [cringe] comment from when I first started with Elm :rofl: )

This is just off the top of my head, and may not apply, but have you also looked into using Web Workers to process that data, so it can be handled on a different thread?

Should mean it won’t make the page unresponsive.

1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.