1
var obj = { 
conn : null,
first : function(thisIdentity) {
    "use strict";
    var myObj = this;
    $(document).on('click', thisIdentity, function(e) {
    e.preventDefault();
    $.ajax ({ 
        url : some value,
        // other parameters
        success : function(data) {
            myObj.conn = new Connection(data.user_id, "127.0.0.1:80");
            sessionStorage.setItem('connection', JSON.stringify(myObj.conn));
           }
        });
   },
second : function(thisIdentity) {
    "use strict";
    var myObj = this;
    var conntn = sessionStorage.getItem('connection');
        $(document).on('click', thisIdentity, function(e) {
        e.preventDefault();
        $.ajax ({ 
            url : some value,
            // other parameters
            success : function(data) { 
            var parsedConnection = JSON.parse(conntn);
            parsedConnection.sendMsg(data.id, data.nid);
        }
      });
    }
};
var Connection = (function() {
    function Connection(uid, url) {
       this.uid = uid;
       this.open = false;
       this.socket = new WebSocket("ws://"+url);
       this.setupConnectionEvents();
    },
Connection.prototype = {
    sendMsg : function(id, nid) {
        alert("Working");
    },
    // other functions
    }
})();

So connection is made in the AJAX callback function of first and I store the object in the sessionStorage via JSON but when I use it in the AJAX callback of second then error is coming that

TypeError: parsedConnection.sendMsg is not a function

Now I understand that may be it is because JSON can be used to store plain objects not prototype-based objects.

My question is : Can any one tell me how to store prototype-based objects via JSON or any other way to implement this?

I don't want to use eval. Any code, reference would be much appreciated. Thanks!

UPDATE

I did as @Dan Prince mentioned but then a new problem occurred that now when in sendMsg function I use

this.socket.send(JSON.stringify({
   action: 'message',
   rec: receiver,
   msg: message
}));

Then it stays

InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable

Any inputs? Thanks!

Yomesh
  • 288
  • 1
  • 4
  • 19
  • Have a look to this [link](http://stackoverflow.com/questions/34413260/how-to-set-value-in-arraylist-without-loading-whole-page/34452118#34452118). I hope it will help you. http://stackoverflow.com/questions/34413260/how-to-set-value-in-arraylist-without-loading-whole-page/34452118#34452118 – Rish Dec 27 '15 at 10:07
  • @Rish so I should create an `array` and add the `object` to it and store that `array` to the `sessionStorage` then fetch that `array` in the second function? Right? – Yomesh Dec 27 '15 at 10:14
  • You can't hope to recreate a socket instance from saved data. The only way back to a socket is to call `new Connection()` again; and since a Connection is defined entirely by `uid` and `url`, that is all the data you need to save. – Roamer-1888 Dec 27 '15 at 13:38
  • @Roamer-1888 Yes I figured. Thanks! – Yomesh Dec 28 '15 at 15:31
  • @Yomesh, I half wrote an answer for you before getting side-tracked. It may still be useful to you so I'll finish it off .... stand by ..... – Roamer-1888 Dec 28 '15 at 17:25

2 Answers2

0

You could probably hack your own solution into place by storing the prototype as a property of the object, then reinstantiating it with Object.create after you read it, but the real question is why do you want to do this in the first place?

I would suggest writing a serialize method on Connection's prototype, which exposes only the essential information (there's no sense serializing a web socket for example).

Connection.prototype.toJSON = function() {
  return JSON.stringify({
    uid: this.uid,
    url: this.url,
    open: this.open
  });
};

Then use this method when you save the connection object into session storage.

myObj.conn = new Connection(data.user_id, "127.0.0.1:80");
sessionStorage.setItem('connection', myObj.conn.toJSON());

Each saved connection now has the minimum amount of data you need to call the constructor and recreate the instance.

When you load a connection from session storage, parse it and pass the values back into the constructor.

var json = sessionStorage.getItem('connection');
var data = JSON.parse(json);
var connection = new Connection(data.uid, data.url)

// ...
connection.sendMsg(data.id, data.nid);

This will recreate the correct prototype chain in a natural and predictable way.

Dan Prince
  • 29,491
  • 13
  • 89
  • 120
  • Okay I did as you mentioned but now I am getting an error **TypeError: myObj.conn.toJSON is not a function** Any thoughts on this? – Yomesh Dec 27 '15 at 10:32
  • Sounds like you haven't added the toJSON method to the prototype for Connection. Should be in the same block as the sendMsg function. – Dan Prince Dec 27 '15 at 10:42
  • I did and it is working now but some more problems popped up! :( Now in `sendMsg` function is I use `this.socket.send()` then it states `InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable`. Problems and problems everywhere! – Yomesh Dec 27 '15 at 11:01
  • If you want to update the question, I'll take a look. – Dan Prince Dec 27 '15 at 11:02
  • `this.socket.send(JSON.stringify({...}););` is throwing this error. – Yomesh Dec 27 '15 at 12:38
  • Is the socket definitely open? The `socket.readyState` should be 1 before you start to send data. – Dan Prince Dec 27 '15 at 12:47
  • yes I figured. Actually when the connection object was created again then due to AJAX async nature `connection.sendMsg` was not waiting for object creation and both creation of object and calling of method was happening at the same time. Therefore, leading to the conflict but I figured it! Now connection is open and sendMsg is also working now I will try and see if it is actually sending the data. still Thanks mate! – Yomesh Dec 28 '15 at 15:31
0

It's hard to see exactly what you are trying to achieve in every respect, but let's assume :

  • for various DOM elements, a click handler (delegated to document) will cause asynchronously derived data to be sent via socket.send().
  • the socket is to be initialized with an asynchronously derived uri.
  • the socket is to be kept available for immediate reuse.
  • data by which the socket is initialized is to be cached in local storage for future sessions. (It makes no sense to store the socket itself).

In addition, we need to acknowledge that a socket consume resources should really be disposed of if its resuse is not immediate.

The whole strategy is abnormally complex. The overhead of performing an ajax operation once per session to obtain a uri would typically be accepted, as would the creation of a socket each time one is needed. However, it's an intersting exercise to write something with all the stated characteristics.

This may not be 100% correct but could possibly give you some ideas, including the use of promises to cater for several asynchronisms. Here goes ...

var obj = {
    conn: null,
    init: function(thisIdentity) {
        // It makes sense to attach the click handler only *once*, so let's assume this is an init function.
        "use strict";
        var myObj = this;
        $(document).on('click', thisIdentity, function(e) {
            e.preventDefault();
            $.ajax ({
                url : some value,
                // other parameters
            }).then(function(data) {
                myObj.send(JSON.stringify({
                    'id': data.id,
                    'nid': data.nid
                }));
            });
        });
    },
    send: function(data) {
        "use strict";
        var myObj = this;
        return myObj.getSocket().then(function(socket) {
            socket.send(data);
        }).then(function() {
            // by disposing in later event turn, a rapid series of send()s has at least a chance of using the same socket instance before it is closed.
            if(socket.bufferedAmount == 0) { // if the socket's send buffer is empty, then dispose of it.
                socket.close();
                myObj.conn = null;
            }
        });
    },
    getSocket: function() {
        "use strict";
        var myObj = this;
        //1. Test whether or not myObj.conn already exists ....
        if(!myObj.conn) {
            //2 .... if not, try to recreate from data stored in local storage ...
            var connectionData = sessionStorage.getItem('connectionData');
            if(connectionData) {
                myObj.conn = myObj.makeSocket(connectionData.user_id);
            } else {
                //3. ... if connectionData is null, perform ajax.
                myObj.conn = $.ajax({
                    url: some value,
                    // other parameters
                }).then(function(data) {
                    sessionStorage.setItem('connectionData', JSON.stringify(data));
                    return myObj.makeSocket(data.user_id);
                });
            }
        }
        return myObj.conn; // note: myObj.conn is a *promise* of a socket, not a socket.
    },
    makeSocket: function(uid) {
        "use strict";
        var myObj = this;
        var uri = "127.0.0.1:80"; // if this is invariant, it can be hard-coded here.

        // return a *promise* of a socket, that will be resolved when the socket's readystate becomes OPEN.
        return $.Deferred(function(dfrd) {
            var socket = new WebSocket("ws://" + uri);
            socket.uid = uid;
            socket.onopen = function() {
                myObj.setupConnectionEvents();// not too sure about this as we don't know what it does.
                dfrd.resolve(socket);
            };
        }).promise();
    }
};

Under this scheme, the click handler or anything else can call obj.send() without needing to worry about the state of the socket. obj.send() will create a socket if necessary.

If you were to drop the requirement for storing data between sessions, then .send() and .getSocket() would simplify to the extent that you would probably choose to roll what remains of .getSocket() into .send().

Roamer-1888
  • 19,138
  • 5
  • 33
  • 44
  • I will try this and will get back to you. Basically I was worried or confused about that suppose if first ajax call created the socket but since JavaScript is a stateless language then that object/socket/connection will be lost on page change or refresh so if from any other node data arrives then how will this node get to know as socket will only re-create at the time of second event. – Yomesh Dec 28 '15 at 22:11
  • If you really want to avoid that issue, I think you have to consider a [Single-page Application (SPA)](https://en.wikipedia.org/wiki/Single-page_application). – Roamer-1888 Dec 28 '15 at 23:16
  • Okay but sites like Facebook, Twitter and likes aren't SPAs if I am not wrong. Is there no work around this? – Yomesh Dec 29 '15 at 05:15
  • Facebook, Twitter and all other sites accept that, on page change, any web workers (sockets) brought into life by the old page will die, and any incomplete requests made by them will never be completed. The new page will be responsible, *in its own right*, for gathering any data/content not initially served as part of the page. One means of performing that gathering is for the new page to create *its own* web workers, which (like other means) may repeat the gathering performed by the old page - inescapably inefficient. – Roamer-1888 Dec 30 '15 at 07:19
  • Questions [here](http://stackoverflow.com/questions/10886910/) and [here](http://stackoverflow.com/questions/12455127/) support your feeling that web workers might sensibly persist from page to page, and the answers support my conclusion that an SPA is the only solution. – Roamer-1888 Dec 30 '15 at 07:19