A lot of the async Rust code I work with already looks like `async fn foo() -> ... { do_request().await?.blah().await }`, plus the occasional gathering of futures into a `Vec` to join on. That sort of thing, not much different from Javascript, but with a lot more control of the low-level details.
A good deal of corner cases should get better once async traits are stabilized, which will mean much less need for manually writing out Future types. But honestly, even now it's not that bad. I have a codebase that uses async to read hundreds of thousands of files[1], streaming gunzip them, pass them to another future which streaming parses records from them, and then pushes those parsed records into a `FnMut` closure for further non-async processing. It took a bit of thinking and design to get everything moving together nicely, but that corner of the codebase now is only ~200 lines of pretty straightforward code -- there's like 1 instance of `Unpin`. It's not that bad.
[1]: I know async isn't necessarily faster for reading files, but it started life doing network requests and it can still saturate a 200-core machine so I haven't felt the need to port it over to threads.