3

Is there any kind of persistence framework for JavaScript and/or the Google v8 engine?

I want to store (serialize) a whole graph of objects (including, e.g., functions) and re-load it later. JSON is not sufficient, since it does not permit functions to be stored and permits only a tree-like structure (i.e. no two objects referencing the same object).

I need to be able to do that generically (i.e. without knowing the JavaScript code at the time at which I write my program embedding v8), since I want the user of my program to be able to customize it with JavaScript, but I need to store the state of my program (including the state of the customization) and re-load it later. Hence I need to store the state of the JavaScript engine.

Edit:

Example:

Suppose we have the following code:

var obj = { a: 4, b: function (x) { return x + this.a; } }
// ...
if ( ... ) { obj.a = 5; }
// ...
if ( ... ) { var c = 1; obj.b = function (x) { return x + this.a + c; } }
// ...
// now I want to serialize obj

Then is it (without any meta-information about the logic of the program) possible to serialize obj and later deserialize it such that obj.b (2) delivers the same result after deserialization as it did before serialization?

Second Edit: Note the closure.

JohnB
  • 13,315
  • 4
  • 38
  • 65
  • I cannot understand why you need to persist functions? Since you can restore functions (assuming methods) from the object prototype inheritances. – Kyaw Tun Sep 24 '12 at 09:32
  • Your question is not entirely clear to me. I will nevertheless try to illustrate my question by an example. – JohnB Sep 25 '12 at 06:52
  • why not just store all the javascript code and then eval to restore it (just like coming back from the server)? or use `toString()` to deserialize each function. again eval cannot be avoid. – Kyaw Tun Sep 25 '12 at 10:31
  • Well, that's a possibility, but not a nice one, since not all data within a running script needs to be generated by the script itself. There might have been, e.g., user input or data obtained from the network or so. Hence I am still looking for something like a serialization framework. Well, I could program one for Google v8, I guess, if that is not beyond the scope of my intellectual capabilities. – JohnB Sep 25 '12 at 17:13
  • I see. prototype inheritance will only work with predefined functions (methods). If the functions are simple, also think about expression in S expression. It avoid eval, but still flexible. – Kyaw Tun Sep 26 '12 at 02:04

3 Answers3

6

Unfortunately, what you're trying to do is not currently possible in Javascript. The reason is that closures are not just objects, they're objects bound to an execution context.

Getting past the "this can't be done in javascript" issue and moving into the "what if wrote a patch for V8 to allow this" phase of the answer, this is conceptually difficult. Essentially, for every closure you'd serialize, you would have to serialize the Context object that the closure exists in. It'd be nice to be able to just serialize the HandleScope, but the nature of closures is that you can't reach inside them.

Okay, so let's say you've written a function that can serialize the Context that the closure exists in, and you can even deserialize it. What do you do with it?

The answer to that is 'not much'. Javascript can only be executed in a single context at a time. The closure that you've deserialized doesn't exists in the context that you're trying to pull it back into. You can't really pass data between contexts, and if your function has data bound to free variables, do you use the ones that exist in the deserializer-invoking context, or do you overwrite it with the deserialized context? Conceptually, this is a nightmare.

Ecmascript Harmony had considered giving us nearly-first-class continuations, but it's been pushed form the discussion which I rant about here, but this isn't going to happen any time soon.

saml
  • 6,702
  • 1
  • 34
  • 30
  • Thank you for this insightful answer. What I try to do is, however, possible in Jurassic (C# JavaScript engine), so it should not be impossible to reach something similar for Google v8. – JohnB Sep 28 '12 at 04:59
  • How do you do it in Jurassic? I've never used it, but I'd be fascinated to know how it works. Architecturally, I'm guessing it's different from V8. – saml Sep 28 '12 at 16:11
0

HTML5 local storage allows persistence at client level through javascript.

I'm not sure if it will fit your needings, as to being able to store a function you'll need to somewhat give it some markup that allows you to deserialize it when retrieving it from storage (or maybe just store it as plain text and try to eval it on retrieval)

http://diveintohtml5.info/storage.html

Bardo
  • 2,470
  • 2
  • 24
  • 42
  • Hm, the problem with storing functions as plain text is that I will lose captured variables if the function involves a closure. – JohnB Sep 25 '12 at 09:11
  • You will need to replicate the values obtained inside of the closure to variables of function's scope. Quite awful, but I supose that it could do the trick. – Bardo Sep 25 '12 at 12:10
  • I think the biggest problem with this suggestion is that it links to w3schools. W3Schools is not a reliable source of any kind of information. – saml Sep 27 '12 at 16:57
0

I don't think persisting functions is a good practice. I can suggest you the below approach. Turn your JSON data to lets say some class like "MyData". You can find two functions fromJSON, toJSON which will do the magic you want.

var MyData = function(props){

    this.temp = "a";

    this.getTemp = function(){
        return this.temp;
    }

    this.fromJSON = function(props){
        if(props){
            this.temp = props.temp;
        }

    }
    this.toJSON = function(){
        var props = {};
        props.temp = this.temp;
        return props;
    }

    this.fromJSON(props);

}

var obj = new MyData({"temp" : "b"});
var state = obj.toJSON();
// persist state about the object as JSON string
LOCALSTORAGE.put(state); // You can write some HTML5 local storage stuff to persist

var persistedState = LOCALSTORAGE.get(); // You can use the above HTML5 local storage stuff to read the persisted stuff
var newBornObj = new MyData(persistedState);
Engineer
  • 227
  • 2
  • 19
  • I think you're missing that he's asked how to persist closures, not JSON. Closures aren't JSON-able. – saml Oct 02 '12 at 18:12