From e4e0610da16cf9a99f25933f3c17a6bc2288845f Mon Sep 17 00:00:00 2001 From: Geoff Schmidt Date: Mon, 27 Oct 2014 06:06:07 -0700 Subject: [PATCH] Move Tracker manual chapter back out to Github again. Provide a shorter readme about it. --- packages/tracker/README.md | 1192 +++--------------------------------- 1 file changed, 90 insertions(+), 1102 deletions(-) diff --git a/packages/tracker/README.md b/packages/tracker/README.md index 4b02e84d19..f6ea93aa29 100644 --- a/packages/tracker/README.md +++ b/packages/tracker/README.md @@ -1,1138 +1,126 @@ # Meteor Tracker -Meteor Tracker (originally "Meteor Deps") is an incredibly tiny (~1k) but incredibly powerful library for **transparent reactive programming** in JavaScript. +Meteor Tracker is an incredibly tiny (~1k) but incredibly powerful +library for **transparent reactive programming** in JavaScript. (It +was previously called Deps.) -## Transparent Reactive Programming +Tracker gives you much of the power of a full-blown +[Functional Reactive Programming](http://en.wikipedia.org/wiki/Functional_reactive_programming) (FRP) system without requiring you to rewrite your program as a FRP data flow graph. Combined with Tracker-aware libraries, this lets you build complex event-driven programs without writing a lot of boilerplate event-handling code. -A basic problem when writing software, especially application software, is monitoring some value – like a record in a database, the currently selected item in a table, the width of a window, or the current time – and updating something whenever that value changes. +Tracker is essentially a simple _convention_, or interface, that lets reactive data sources (like your database) talk to reactive data consumers (such as a live-updating HTML templating library) without the application code in between having to be involved. Since the convention is very simple, it is quick and easy for library authors to make their libraries Tracker-aware, so that they can participate in Tracker reactivity. -There are several common patterns for expressing this idea in code, including: +This README has a short introduction to Tracker. For a complete guide +to Tracker, consult the thorough and informative [Tracker +Manual](https://github.com/meteor/meteor/wiki/Tracker-Manual), which +is five times longer than the Tracker source code itself. You can also browse the API reference on the [main Meteor docs page](http://docs.meteor.com/#tracker). -* **Poll and diff.** Periodically (every second, for example), fetch the current value of the thing, see if it's changed, and if so perform the update. +## Example -* **Events.** The thing that can change emits an event when it changes. Another part of the program (often called a controller) arranges to listen for this event, and get the current value and perform the update when the event fires. +Take this ordinary JavaScript function: -* **Bindings.** Values are represented by objects that implement some interface, like BindableValue. Then a 'bind' method is used to tie two BindableValues together so that when one value changes, the other is updated automatically. Sometimes as part of setting up the binding, a transformation function can be specified. For example, Foo could be bound to Bar with the transformation function of toUpperCase. +``` +var currentTemperatureFahrenheit = function () { + return currentTemperatureCelsius() * 9/5 + 32; +}; -Another pattern, not yet as commonly used but very well suited for complex modern apps, is **reactive programming**. A reactive programming system works like a spreadsheet. The programmer says, "the contents of cell A3 should be equal to the sum of cells B1-B6, multiplied by the value of cell C4", and the spreadsheet is responsible for automatically modeling the flow of data between the cells, so that when cell B2 changes the value of cell A3 will be automatically updated. +``` -So reactive programming is a **declarative** style of programming, in which the programmer says what should happen (A3 should be kept equal to the result of a certain computation over the other cells), not how it should happen, as in imperative programming. +We can call it for its value (assuming there's a `currentTemperatureCelsius` function): -Reactive programming is perfect for building user interfaces, because instead of attempting to model all interactions in a single piece of cohesive code the programmer can express what should happen upon specific changes. The paradigm of responding to a change is simpler to understand than modeling which changes affect the state of the program explicitly. For example, suppose that we are writing an HTML5 app with a table of items, and the user can click on an item to select it, or ctrl-click to select multiple items. We might have a `

` tag and want the contents of the tag to be equal to the name of the currently selected item, capitalized, or else "Multiple selection" if multiple items are selected. And we might have a set of `` tags and want the CSS class on each `` to be 'selected' if the items corresponding to that row is in the set of selected items, or the empty string otherwise. +``` +> currentTemperatureFahrenheit() +71.8 +``` -Reactive programming is a perfect fit for a situation like this: +But, if the `currentTemperatureCelsius` function is Tracker-aware (or even if it's not, but as long it reads the current temperature ultimately from some Tracker-aware data source), then we can also call `currentTemperatureFahrenheit` _reactively_: -* If we use **poll and diff**, the UI will be unacceptably laggy. After the user clicks, the screen won't actually update until the next polling cycle. Also, we have to store the old selection set and diff it against the new selection set, which is a bit of a hassle. +``` +> var handle = Tracker.autorun(function () { + console.log("The current temperature is", currentTemperatureFahrenheit(), + "F"); + }); +The current temperature is 71.8 F (printed immediately) +The current temperature is 71.9 F (printed a few minutes later) +> handle.stop(); (stop temperature changes from printing) -* If we use **events**, we have to write some fairly tangled controller code to manually map changes to the selection, or to the name of the selected item, onto updates to the UI. For example, when the selection changes we have to remember to update both the `

` and (typically) two affected ``s. What's more, when the selection changes we have to automatically register an event handler on the newly select item so that we can remember to update the `

`. This controller code is hard to structure cleanly and to maintain, especially as the UI is extended and redesigned. +``` -* If we use **bindings**, we will have to use a complex DSL (domain specific language) to express the complex relationships between the variables. The DSL will have to include indirection (bind the contents of the `

` not to the name of any fixed item, but to the item indicated by the current selection), transformation (capitalize the name), and conditionals (if more than one item is selected, show a placeholder string). +The function passed to `Tracker.autorun` is called once immediately, and then it's called again whenever there are any changes to any of the _reactive data sources_ that it referenced. To make this work, `currentTemperatureCelsius` just needs to register with Tracker as a reactive data source when it's called, which takes only a few lines of code. -Reactive programming promises to let us express this problem exactly as we think about it, giving us concise, readable, maintainable code. The only problem? Historically, reactive programming systems have been too complicated and slow for most people to use in production. They required reactive expressions to be modeled as a tree of nodes, and had to run an expensive dataflow analysis every time a change happened in order to know what to update. +Or, instead of calling `Tracker.autorun` ourselves, we might use `currentTemperatureFahrenheit` in a [Blaze](https://www.meteor.com/blaze) template: -Meteor Tracker is a new reactive programming system that is incredibly simple and lightweight. It is **small** (around 1kb, gzipped and minifed), **simple** (you just write normal JavaScript and it's automatically reactive!), and **fast** (no expensive dataflow analysis – a reactive update is about as expensive as firing an event). +``` + +