A more responsive Flow

Flow v0.92 responds to requests during rechecks

Photo by Matthew Brodeur on Unsplash

When editing Flow code in an IDE, users expect features like autocompletion and jump-to-definition to work. However, the Flow support for these features often stops working temporarily after saving or rebasing. Flow v0.92 addresses this poor user experience.

The problem

Commands like flow autocomplete and flow get-def (and their LSP counterparts textDocument/completion and textDocument/definition) are already typically very fast for the Flow server to run. If you need autocompletion in the file foo.js, Flow will just quickly typecheck your local foo.js buffer (in case you made changes) and return the suggestions. This typechecking usually takes the server tens of milliseconds to run, since a running Flow server has already computed the types of all the imported modules.

So if running these commands is so fast, why was Flow so slow at responding to many of these commands?

It was because the Flow server was often busy rechecking the codebase. When you save a file, Flow notices the change and starts updating its type information. Flow could not respond to commands like flow autocomplete until the recheck had finished for two main reasons:

  1. Commands like flow autocomplete need the type information for all the imported modules. But rechecks happen because Flow needs to recompute type information, so during a recheck we won’t necessarily have up-to-date type information. Without up-to-date type information, Flow might answer some commands incorrectly.
  2. The Flow server wasn’t architected to do more than one thing at once. Flow was single threaded and sloppy with how it read and wrote state.

The solution

We addressed reason #1 by using out-of-date type information. We can just use type information from before the recheck to respond to requests. While using out-of-date information could lead to commands like flow autocomplete returning incorrect results, it is relatively rare and a price worth paying for the responsiveness.

We addressed reason #2 with a year-long re-architecture of Flow server’s internals. We are now more rigorous with how we read and write state and have heavily integrated with the fantastic Lwt library, a cooperative threading library for OCaml.

Try it out!

Starting in v0.92.1, Flow now responds to many CLI and LSP commands immediately, without waiting for the recheck to finish. At Facebook, we’re seeing a big drop in response times for Flow requests send from our IDEs. textDocument/completion's average response time has dropped ~75% and the p90 response time has dropped ~95%. Hopefully this change will improve your experience with Flow too!

If this causes any trouble for you, you can disable this behavior in the .flowconfig with

[options]
wait_for_recheck=true

or for an individual CLI command with the --wait-for-recheck true option.

Hope this helps! Enjoy!