在sessionStorage中保存基于JavaScript原型的对象?

时间:2022-08-26 08:18:39
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

所以首先在AJAX回调函数中建立连接,然后我通过JSON将对象存储在sessionStorage中,但是当我在第二个AJAX回调中使用它时,错误即将到来

TypeError: parsedConnection.sendMsg is not a function

TypeError:parsedConnection.sendMsg不是函数

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

现在我明白了可能是因为JSON可以用来存储普通对象而不是基于原型的对象。

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!

我不想使用eval。任何代码,参考将非常感激。谢谢!

UPDATE

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

我在@Dan Prince提到的时候做了,但是当我在sendMsg函数中使用时出现了一个新问题

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

InvalidStateError:尝试使用不可用或不再可用的对象

Any inputs? Thanks!

有什么输入?谢谢!

2 个解决方案

#1


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?

您可以通过将原型存储为对象的属性来破解您自己的解决方案,然后在阅读后使用Object.create重新实现它,但真正的问题是您为什么要首先执行此操作?

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的原型上编写一个序列化方法,它只公开基本信息(例如,序列化Web套接字没有意义)。

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.

这将以自然且可预测的方式重建正确的原型链。

#2


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().
  • 对于各种DOM元素,单击处理程序(委托给文档)将导致通过socket.send()发送异步派生的数据。

  • the socket is to be initialized with an asynchronously derived uri.
  • 套接字将使用异步派生的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.

整个战略异常复杂。通常每个会话执行一次ajax操作以获得uri的开销,以及每次需要时创建套接字的开销。然而,写一些具有所有特征的东西是一种有趣的练习。

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 ...

这可能不是100%正确,但可能会给你一些想法,包括使用承诺来满足几个异步。开始 ...

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.

在此方案下,单击处理程序或其他任何东西都可以调用obj.send()而无需担心套接字的状态。如有必要,obj.send()将创建一个套接字。

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().

如果你要删除在会话之间存储数据的要求,那么.send()和.getSocket()会简化到你可能选择将剩余的.getSocket()转换为.send()的程度。

#1


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?

您可以通过将原型存储为对象的属性来破解您自己的解决方案,然后在阅读后使用Object.create重新实现它,但真正的问题是您为什么要首先执行此操作?

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的原型上编写一个序列化方法,它只公开基本信息(例如,序列化Web套接字没有意义)。

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.

这将以自然且可预测的方式重建正确的原型链。

#2


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().
  • 对于各种DOM元素,单击处理程序(委托给文档)将导致通过socket.send()发送异步派生的数据。

  • the socket is to be initialized with an asynchronously derived uri.
  • 套接字将使用异步派生的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.

整个战略异常复杂。通常每个会话执行一次ajax操作以获得uri的开销,以及每次需要时创建套接字的开销。然而,写一些具有所有特征的东西是一种有趣的练习。

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 ...

这可能不是100%正确,但可能会给你一些想法,包括使用承诺来满足几个异步。开始 ...

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.

在此方案下,单击处理程序或其他任何东西都可以调用obj.send()而无需担心套接字的状态。如有必要,obj.send()将创建一个套接字。

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().

如果你要删除在会话之间存储数据的要求,那么.send()和.getSocket()会简化到你可能选择将剩余的.getSocket()转换为.send()的程度。