From 7ca2e125c17bd541340bce55623bd40cf88ce64f Mon Sep 17 00:00:00 2001 From: Li Haoyi Date: Thu, 20 Nov 2014 02:07:02 -0800 Subject: Scala-async chapter works --- book/src/main/scalatex/book/Index.scalatex | 63 +++--- .../book/indepth/AdvancedTechniques.scalatex | 252 +++++++++++++++++++++ examples/demos/build.sbt | 6 +- examples/demos/src/main/scala/advanced/Async.scala | 120 ++++++++++ .../demos/src/main/scala/advanced/BasicRx.scala | 80 +++++++ .../demos/src/main/scala/advanced/Futures.scala | 13 ++ .../src/main/scala/scrollmenu/Controller.scala | 3 + 7 files changed, 506 insertions(+), 31 deletions(-) create mode 100644 book/src/main/scalatex/book/indepth/AdvancedTechniques.scalatex create mode 100644 examples/demos/src/main/scala/advanced/Async.scala create mode 100644 examples/demos/src/main/scala/advanced/BasicRx.scala create mode 100644 examples/demos/src/main/scala/advanced/Futures.scala diff --git a/book/src/main/scalatex/book/Index.scalatex b/book/src/main/scalatex/book/Index.scalatex index e9a8fc8..c834bb0 100644 --- a/book/src/main/scalatex/book/Index.scalatex +++ b/book/src/main/scalatex/book/Index.scalatex @@ -17,46 +17,49 @@ @p This book does not spend time on pontifying a philosophy or ideology behind Scala.js or Scala. It instead spends its words on hands-on tutorials and in-depth dives into parts of the Scala.js platform, to try and get you acquainted with Scala.js as soon as possible, so you can make your own decisions about its merits or qualities. - @sect("Intro to Scala.js") - @Intro() +@sect("Intro to Scala.js") + @Intro() - @sect("Hands On", "Writing your first Scala.js programs") - @p - This half of the book walks you through various facets of the Scala.js development experience. From making your first app, to testing and publishing modules, to writing an integrated client-server application. +@sect("Hands On", "Writing your first Scala.js programs") + @p + This half of the book walks you through various facets of the Scala.js development experience. From making your first app, to testing and publishing modules, to writing an integrated client-server application. + + @sect("Getting Started") + @handson.GettingStarted() - @sect("Getting Started") - @handson.GettingStarted() + @sect("Making a Canvas App") + @handson.CanvasApp() - @sect("Making a Canvas App") - @handson.CanvasApp() + @sect("Interactive Web Pages") + @handson.WebPage() - @sect("Interactive Web Pages") - @handson.WebPage() + @sect("The Command Line") + @handson.CommandLine() - @sect("The Command Line") - @handson.CommandLine() + @sect("Cross Publishing Libraries") + @handson.PublishingModules() - @sect("Cross Publishing Libraries") - @handson.PublishingModules() + @sect("Integrating Client-Server") + @handson.ClientServer() - @sect("Integrating Client-Server") - @handson.ClientServer() +@sect("In Depth", "Exploring Scala.js") + @p + This half of the book dives into a few aspects of Scala.js much more deeply that the hands-on introduction does. It's aimed at someone who has already used Scala.js, and wants to explore the edge-cases, how things work under-the-cover, or why it has been designed in such a way. It's not a formal specification; rather, it's aim is to be a useful reference to read instead of (or in preparation for) digging into the implementation code. - @sect("In Depth", "Exploring Scala.js") - @p - This half of the book dives into a few aspects of Scala.js much more deeply that the hands-on introduction does. It's aimed at someone who has already used Scala.js, and wants to explore the edge-cases, how things work under-the-cover, or why it has been designed in such a way. It's not a formal specification; rather, it's aim is to be a useful reference to read instead of (or in preparation for) digging into the implementation code. + @sect("Advanced Techniques") + @indepth.AdvancedTechniques() - @sect("Javascript Interoperability") - @indepth.JavascriptInterop() + @sect("Javascript Interoperability") + @indepth.JavascriptInterop() - @sect("Deviations from Scala-JVM") - @indepth.SemanticDifferences() + @sect("Deviations from Scala-JVM") + @indepth.SemanticDifferences() - @sect("The Compilation Pipeline") - @indepth.CompilationPipeline() + @sect("The Compilation Pipeline") + @indepth.CompilationPipeline() - @sect("Scala.js' Design Space") - @indepth.DesignSpace() + @sect("Scala.js' Design Space") + @indepth.DesignSpace() - @sect("Java APIs") - @indepth.JavaAPIs() \ No newline at end of file + @sect("Java APIs") + @indepth.JavaAPIs() \ No newline at end of file diff --git a/book/src/main/scalatex/book/indepth/AdvancedTechniques.scalatex b/book/src/main/scalatex/book/indepth/AdvancedTechniques.scalatex new file mode 100644 index 0000000..1b1f092 --- /dev/null +++ b/book/src/main/scalatex/book/indepth/AdvancedTechniques.scalatex @@ -0,0 +1,252 @@ +@p + @sect.ref{Getting Started} walks you through how to set up some basic Scala.js applications, but that only scratches the surface of the things you can do with Scala.js. Apart from being able to use the same techniques you're used to in Scala-JVM in the browser, Scala.js opens up a whole range of possibilities and novel techniques that are not found in typical Scala-JVM applications. + +@p + Although these techniques may technically be possible on the JVM, very few Scala-JVM applications are built in a way that can take advantage of them. Most Scala-JVM code runs on back-end servers which have a completely different structure from the client-side apps that Scala.js allows. +@p + This client-side user-interface-focused code lends itself to completely different design patterns from those used to develop server-side code. This section will explore a number of techniques which are present + +@ul + @li + @sect.ref("Functional-Reactive UIs", "Functional-reactive user interfaces") + @li + @sect.ref("Transparent RPCs", "Transparent client-server RPCs") + @li + @sect.ref("Asynchronous Workflows", "Asynchronous user-interation workflows") + +@p + One note is that these are "Techniques" rather than "Libraries" because they have not been packaged up in a way that is sufficiently nice that you can use them out-of-the-box just by adding a dependency somewhere. Thus, they each require some small amount of boilerplate before use, though the amount of boilerplate is fixed: it does not grow with the size of your program, and anyway gives you a chance to tweak it to do exactly what you want. + +@sect{Functional-Reactive UIs} + @p + @lnk("Functional-reactive Programming", "http://en.wikipedia.org/wiki/Functional_reactive_programming") (FRP) is a field with encompasses several things: + + @ul + @li + @b{Discrete}: Handling of first-class event-streams like in @link("RxJS", "https://github.com/Reactive-Extensions/RxJS") + @li + @b{Continuous}: Handling of first-class signals, like in @link("Elm", "http://elm-lang.org/learn/What-is-FRP.elm") + + @sect{Why FPR} + @p + The value proposition of FRP is that in a "traditional" program, when an event occurs, events and changes propagate throughout the program in an ad-hoc manner. An event-listener may trigger additional events, call some callbacks, or set some mutable variables that subsequent code will read and react to. + + @p + This works, but the ad-hoc nature is both free-ing and limiting. You are free to do whatever you want in response to any action, but in return the developer who maintains your code (e.g. yourself 6 months from now) has no idea what your code is doing in response to any action: the possible consequence of an action is basically "Anything"! + + @p + Furthermore, because the propagation is ad-hoc, there is no way for the code to help ensure that you are propagating changes in a "valid" manner: it is thus easy for programmer errors to result in changes or events being incorrectly propagated. This most often results in data falling out of sync: a UI widget may forget to update when an action is taken, resulting in an inconsistent state being shown to the user, ultimately resulting in confused users. + + @p + FRP basically structures these event- or change-propagations as first-class values within the program, either as an @hl.scala{EventSource[T]} type that represents a discrete source of individual @hl.scala{T} events, or as a @hl.scala{Signal[T]} type which represents a continuous time-varying value @hl.scala{T}. This comes at some cost within the program: you now have to program using these @hl.scala{EventSource}s or @hl.scala{Signal}s, rather than just ad-hoc running callbacks or listening-to/triggering events all over the place. In exchange, you get more powerful tools to work with these values, making it easy for the library to e.g. ensure that changes always propagate correctly throughout your program, and that all values are always kept in sync. + + @sect{FRP with Scala.Rx} + @p + @lnk("Scala.Rx", "https://github.com/lihaoyi/scala.rx") is a change-propagation library that implements the @b{Continuous} style of FRP. To begin with, we need to include it in our @code{build.sbt} dependencies: + + @hl.ref("examples/demos/build.sbt", "com.scalarx") + + @p + Scala.Rx provides you with smart variables that automatically track dependencies with each other, such that if one smart variable changes, the rest re-compute immediately and automatically. The main primitives in Scala.Rx are: + + @ul + @li + @b{Var}s: Smart variables that can be set manually, and automatically notify their dependents that they need to recompute + @li + @b{Rx}s: Smart values which are set as some computation of other @b{Rx}s or @b{Var}s, which recompute automatically when their dependencies change, and notify their dependents + @li + @b{Obs}s: Observers on either an @b{Rx} or a @b{Var}, which performs some action when it changes + + @p + @hl.scala{Var}s and @hl.scala{Rx}s roughly correspond to the idea of a @hl.scala{Signal} described earlier. The documentation for Scala.Rx goes into this in much more detail, so if you're curious you should read it. This section will jump straight into how to use Scala.Rx with Scala.js. + + @p + To begin with, let's set up our imports: + + @hl.ref("examples/demos/src/main/scala/advanced/BasicRx.scala", "package advanced", "@JSExport") + + @p + Here we are seeing the same @hl.scala{dom} and @hl.scala{scalatags}, imports we saw in the hands-on tutorial, as well a new @hl.scala{import rx._} which bring all the Scala.Rx names into the local namespace. + + @p + Scala.Rx does not "natively" bind to Scalatags, but integrating them yourself is simple enough that it's not worth putting into a separate library. He's a simple integration: + + @hl.ref("examples/demos/src/main/scala/advanced/BasicRx.scala", "implicit def") + + @p + Scalatags requires that anything you want to embed in a Scalatags fragment be implicitly convertible to @hl.scala{Frag}; here we are providing one for any Scala.Rx @hl.scala{Rx[T]}s, as long as the @hl.scala{T} provided is itself convertible to a @hl.scala{Frag}. We call @hl.scala{r().render} to extract the "current" value of the @hl.scala{Rx}, and then set up an @hl.scala{Obs} that watches the @hl.scala{Rx}, replacing the previous value with the current one every time its value changes. + + @p + Now that the set-up is out of the way, let's consider a simple HTML widhet that lets you enter text in a @hl.html{