Translation Tool
For browsers that do not yet support JavaScript Proxies (soon to be Direct-Proxies), code that is run within an AtomizeJS transaction must be translated. AtomizeJS comes with a translation tool which does this.
After doing an npm install atomize-client
, you should find npm
has
installed an atomize-translate
binary.
Usage
atomize-translate
input
output
atomizeVar
[ignore
...]
input
: The path to the input file. The input file must be a pure JavaScript file, not be an HTML file with JavaScript embedded.output
: The path to the output file.atomizeVar
: The name of theatomize
variable, i.e. variable to which the resultnew Atomize(URL)
is assigned. A limitation of using the translation tool is that it is assumed this variable is both global, and that only one AtomizeJS server is ever connected to at any one time.- [
ignore
...]: Names of variables that should be excluded from translation. This list always implicitly contains theatomizeVar
.
The tool should be run on any JavaScript file that contains code that
can be reached from within an AtomizeJS transaction. For example, if
you have the code in ball.js.raw
:
var server = new Atomize("http://localhost:9999/atomize");
function Ball (x, y) {
this.x = x;
this.y = y;
this.raw = server.lift({x: x, y: y});
}
Ball.prototype = {
bounce: function () {
var self = this;
server.atomically(function () {
self.raw.y = -self.raw.y;
}, function (y) {
self.y = y;
});
}
};
Then you should run the translation tool as
atomize-translate ball.js.raw ball.js server Ball this
This will ensure that the Ball
object itself and this
is left
untouched, even though the functions within the Ball
object will be
translated correctly. However, if in the transaction you manipulated
the global Ball
object itself (rather than an instance of the Ball
object) then it would be wrong to have Ball
in the ignored list.
It is normally safe to leave the [ignore
...] list empty. However,
doing so will likely result in the connection to the AtomizeJS server
being required as the source code is itself being loaded by the
browser. Thus in the above example, as the connection to the server is
established as the first line, there would be no problem in leaving
the [ignore
...] field empty. But were the connection established
in some other function later on, the ball.js
file would fail to load
if the [ignore
...] field does not contain the global Ball
.
In general, global variables which are accessed and assigned to as
part of loading the JavaScript file may well need to be provided to
the [ignore
...] field.
Also note that if in your transactions you call functions that reside in other files, you should run the translation tool on those files too.
You must also <script/>
-include the
compat.js
library before the
atomize.js
library in the browser. It does no harm to load this
compat.js
library even on bleeding-edge browsers: the library will detect
whether or not it's really needed and act accordingly.
Under the bonnet
AtomizeJS relies on proxies. A proxy gives the programmer the ability
to intercept all actions upon an object and AtomizeJS needs this to
be able to figure out the actions that are performed as part of a
transaction: to intercept and record these actions as part of the
transaction log. Thus even if you have a[x] = 5
, the proxy will
ensure that the assignment will be intercepted regardless of where the
value of x
came from - it might even come directly from the user.
If the browser does not support proxies then there's not much you can
do without re-writing the code, and that's what the translation tool
does. Yes, you could use the Object.defineProperty
to implement
getters and setters, but that only works for existing properties. If
you have var a = {}, x = Math.random(); a[x] = 'hello';
then you
can't intercept the assignment to a new field by using
Object.defineProperty
.
The translation tool thus rewrites all assignments, accesses, for a
in b
iterations, a in b
checks, and delete
operations to
explicitly go via an extended AtomizeJS API. Thus assuming the
connection to the AtomizeJS server is assigned to a variable called
atomize
, the translation tool will, for example, rewrite
a[x] = 5;
into
atomize.assign(a, x, 5);
and will rewrite
a.b = c[d];
into
atomize.assign(a, 'b', atomize.access(c, [d]));
There is nothing to stop you from writing code which uses this API directly, and indeed if you do so, then you will not need to use the translation tool at all, and your code will work in both old and new browsers. But it does make the code a little less concise.