Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kino.Input.text slow to render new input #345

Closed
clayscode opened this issue Sep 17, 2023 · 7 comments · Fixed by livebook-dev/livebook#2219
Closed

Kino.Input.text slow to render new input #345

clayscode opened this issue Sep 17, 2023 · 7 comments · Fixed by livebook-dev/livebook#2219

Comments

@clayscode
Copy link

Hi all,

I'm having an issue with Kino.Input.text rendering the output very slowly. Sometimes I even have to click around the page a few times or move the element around before the input gets rendered.

Livebook Version: v0.10.0
Elixir Version: v1.15.2

Mix.install([
  {:kino_db, "~> 0.2.1"},
  {:postgrex, "~> 0.17"},
  {:kino_explorer, "~> 0.1.4"},
  {:adbc, "~> 0.1"}
])

alias Explorer.DataFrame, as: DF
alias Explorer.Series, as: Series
alias Explorer.Query, as: Query
frame = Kino.Frame.new()
button = Kino.Control.button("Click") |> Kino.render()
items = [[a: "a", b: "b"], [a: "c",b: "d"]]
Kino.animate(button, 0, fn _event, counter ->
  new_counter = counter + 1
  current = Enum.at(items, counter)

  inputs = [
    example_a: Kino.Input.text("Example a: ", default: "#{current[:a]}"),
    example_b: Kino.Input.text("Example b: ", default: "#{current[:b]}")
  ]
  form = Kino.Control.form(inputs, submit: "Send")
  Kino.Frame.clear(frame)
  Kino.Frame.render(frame, form)

  {:cont, frame, new_counter}
end)

The purpose of the above is to iterate over some objects and fill in the default Kino.Input.text values with them. However, when the input boxes are rendered, they're blank and it often takes a few seconds the default values to show up. If I move the element up or down, they populate the input box immediately. The frame clear and render at the end isn't necessary - I was just trying to see if I could force the text to render some how. Any idea what might be going on?

@josevalim
Copy link
Contributor

josevalim commented Sep 17, 2023

animate already keeps a frame for you, so I wonder if the issue is being caused by rendering the same frame twice. Try this instead:

button = Kino.Control.button("Click") |> Kino.render()
items = [[a: "a", b: "b"], [a: "c",b: "d"]]

Kino.animate(button, 0, fn _event, counter ->
  new_counter = counter + 1
  current = Enum.at(items, counter)

  inputs = [
    example_a: Kino.Input.text("Example a: ", default: "#{current[:a]}"),
    example_b: Kino.Input.text("Example b: ", default: "#{current[:b]}")
  ]
  form = Kino.Control.form(inputs, submit: "Send")
  {:cont, form, new_counter}
end)

@clayscode
Copy link
Author

clayscode commented Sep 17, 2023

animate already keeps a frame for you, so I wonder if the issue is being caused by rendering the same frame twice. Try this instead:

button = Kino.Control.button("Click") |> Kino.render()
items = [[a: "a", b: "b"], [a: "c",b: "d"]]

Kino.animate(button, 0, fn _event, counter ->
  new_counter = counter + 1
  current = Enum.at(items, counter)

  inputs = [
    example_a: Kino.Input.text("Example a: ", default: "#{current[:a]}"),
    example_b: Kino.Input.text("Example b: ", default: "#{current[:b]}")
  ]
  form = Kino.Control.form(inputs, submit: "Send")
  {:cont, form, new_counter}
end)

Still have the same issue with this code

Edit: Just to confirm it's not an issue with my browser, I switched from Firefox to Chrome, but still run into the same problem.

@jannikbecher
Copy link
Contributor

jannikbecher commented Sep 17, 2023

I think there is a race condition happening in

kino/lib/kino/frame.ex

Lines 172 to 177 in f961f8d

def handle_call({:render, term, destination}, _from, state) do
output = Kino.Render.to_livebook(term)
put_update(destination, state.ref, [output], :replace)
state = update_outputs(state, destination, fn _ -> [output] end)
{:reply, :ok, state}
end

When putting an inspect after output

 def handle_call({:render, term, destination}, _from, state) do 
   output = Kino.Render.to_livebook(term) |> IO.inspect()
   put_update(destination, state.ref, [output], :replace) 
   state = update_outputs(state, destination, fn _ -> [output] end) 
   {:reply, :ok, state} 
 end 

it magically works :-D
Couldn't figure out the details yet.

Here is a simple way to reproduce the error:

frame = Kino.Frame.new()
Kino.Frame.render(frame, Kino.Input.text("Test"))

@clayscode
Copy link
Author

clayscode commented Sep 18, 2023

button = Kino.Control.button("Click") |> Kino.render()
items = [[a: "a", b: "b"], [a: "c",b: "d"]]

Kino.animate(button, 0, fn _event, counter ->
  new_counter = counter + 1
  current = Enum.at(items, counter)

  inputs = [
    example_a: Kino.Input.text("Example a: ", default: "#{current[:a]}"),
    example_b: Kino.Input.text("Example b: ", default: "#{current[:b]}")
  ]
  form = Kino.Control.form(inputs, submit: "Send")
  {:cont, form, new_counter}
end)

In the latest Livebook nightly build, this example doesn't even work - the whole session crashes 😅

@clayscode
Copy link
Author

I think there is a race condition happening in

kino/lib/kino/frame.ex

Lines 172 to 177 in f961f8d

def handle_call({:render, term, destination}, _from, state) do
output = Kino.Render.to_livebook(term)
put_update(destination, state.ref, [output], :replace)
state = update_outputs(state, destination, fn _ -> [output] end)
{:reply, :ok, state}
end

When putting an inspect after output

 def handle_call({:render, term, destination}, _from, state) do 
   output = Kino.Render.to_livebook(term) |> IO.inspect()
   put_update(destination, state.ref, [output], :replace) 
   state = update_outputs(state, destination, fn _ -> [output] end) 
   {:reply, :ok, state} 
 end 

it magically works :-D Couldn't figure out the details yet.

Here is a simple way to reproduce the error:

frame = Kino.Frame.new()
Kino.Frame.render(frame, Kino.Input.text("Test"))

I can't replicate my issue with this code - this seems to render correctly. I checked out the .10 branch of both Livebook and Kino and changed it to output = Kino.Render.to_livebook(term) |> IO.inspect() but that doesn't seem to resolve the issue with Kino.animate

@jannikbecher
Copy link
Contributor

@clayscode I pushed a fix to livebook main. Not sure if its the correct way to tackle the issue, but it works on my side.
Lets see what @jonatanklosko thinks :)

@clayscode
Copy link
Author

@jannikbecher your PR seems to fix my issue, awesome!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants