【问题标题】:Save JavaScript prototype based objects in sessionStorage?在 sessionStorage 中保存基于 JavaScript 原型的对象?
【发布时间】:2016-04-01 11:10:57
【问题描述】:
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
    }
})();

所以在第一个的 AJAX 回调函数中建立了连接,我通过 JSON 将对象存储在 sessionStorage 中,但是当我在第二个的 AJAX 回调中使用它时,就会出现错误

TypeError: parsedConnection.sendMsg 不是函数

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

我的问题是:谁能告诉我如何通过 JSON 或任何其他方式来存储基于原型的对象来实现这一点?

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

更新

我按照@Dan Prince 所说的做了,但后来出现了一个新问题,现在在sendMsg 函数中我使用了

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

然后就这样了

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

任何输入?谢谢!

【问题讨论】:

  • 看看这个link。我希望它会帮助你。 stackoverflow.com/questions/34413260/…
  • @Rish 所以我应该创建一个array 并将object 添加到其中并将array 存储到sessionStorage 然后在第二个函数中获取array?对吗?
  • 您不能希望从保存的数据中重新创建套接字实例。返回套接字的唯一方法是再次调用new Connection();并且由于连接完全由uidurl 定义,这就是您需要保存的所有数据。
  • @Roamer-1888 是的,我想通了。谢谢!
  • @Yomesh,在偏离轨道之前,我为你写了一半的答案。它可能对你仍然有用,所以我会完成它......待命......

标签: javascript jquery json ajax sessionstorage


【解决方案1】:

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

我建议在Connection 的原型上编写一个序列化方法,它只公开基本信息(例如,序列化网络套接字是没有意义的)。

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

然后在将连接对象保存到会话存储中时使用此方法。

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

现在每个保存的连接都具有调用构造函数和重新创建实例所需的最少数据量。

当您从会话存储中加载连接时,对其进行解析并将值传回构造函数。

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

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

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

【讨论】:

  • 好的,我按照你说的做了,但现在我收到一个错误 TypeError: myObj.conn.toJSON is not a function 对此有什么想法吗?
  • 听起来您还没有将 toJSON 方法添加到 Connection 的原型中。应该与 sendMsg 函数在同一个块中。
  • 我做到了,现在它正在工作,但出现了更多问题! :( 现在在sendMsg 函数中我使用this.socket.send() 然后它声明InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable。问题和问题无处不在!
  • 如果你想更新问题,我去看看。
  • this.socket.send(JSON.stringify({...});); 抛出此错误。
【解决方案2】:

很难确切地看出你在各个方面想要达到的目标,但让我们假设:

  • 对于各种 DOM 元素,单击处理程序(委托给文档)将导致通过 socket.send() 发送异步派生数据。
  • 将使用异步派生的 uri 初始化套接字。
  • 套接字应保持可用以供立即重复使用。
  • 初始化套接字的数据将被缓存在本地存储中以供将来的会话使用。 (存储套接字本身没有意义)。

此外,我们需要承认,如果不能立即重新使用套接字消耗的资源,那么它确实应该被处理掉。

整个策略异常复杂。通常可以接受每个会话执行一次 ajax 操作以获取 uri 的开销,就像每次需要创建套接字时一样。但是,编写具有所有所述特征的内容是一项有趣的练习。

这可能不是 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();
    }
};

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

如果您要放弃在会话之间存储数据的要求,那么.send().getSocket() 将简化到您可能会选择将剩余的.getSocket() 滚动到.send()

【讨论】:

  • 我会试试这个,然后会回复你。基本上我对此感到担心或困惑,假设如果第一个 ajax 调用创建了套接字,但由于 JavaScript 是一种无状态语言,那么该对象/套接字/连接将在页面更改或刷新时丢失,所以如果来自任何其他节点的数据到达,那么这将如何节点知道套接字只会在第二个事件发生时重新创建。
  • 如果你真的想避免这个问题,我认为你必须考虑Single-page Application (SPA)
  • 好的,但如果我没记错的话,像 Facebook、Twitter 和点赞这样的网站不是 SPA。没有解决办法吗?
  • Facebook、Twitter 和所有其他网站都承认,在页面更改时,任何由旧页面激活的 Web Worker(套接字)都将死亡,并且他们提出的任何不完整的请求将永远不会完成。新页面将以自己的权利负责收集最初未作为页面一部分提供的任何数据/内容。执行该收集的一种方法是让新页面创建它自己的网络工作者,这(与其他方式一样)可能会重复旧页面执行的收集 - 不可避免地低效。
  • 问题herehere 支持您的感觉,即网络工作者可能会明智地从一个页面到另一个页面,而答案支持我的结论,即SPA 是唯一的解决方案。
猜你喜欢
  • 2011-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多