简体   繁体   English

修改函数内部的JavaScript对象,出错返回原样

[英]Modify JavaScript object inside function, return to original if error

I've got a JavaScript object in JSON format that needs to be modified based of a set input (delete foo or add bar, etc).我有一个 JSON 格式的 JavaScript 对象,需要根据设置的输入(删除 foo 或添加栏等)进行修改。 This input can have cascading effects (delete foo might require foobar to be deleted first, based on a set of rules).此输入可能具有级联效果(根据一组规则,删除 foo 可能需要先删除 foobar)。 If half way through a cascade something breaks I don't want the JavaScript object with half the modifications, I want to go back to the original unmodified object.如果在级联的中途出现某些问题,我不希望 JavaScript 对象有一半的修改,我想回到原始的未修改对象。

I could obviously just send a copy of the object into the modification function then not replace the original if the function returns an error.显然,我可以将对象的副本发送到修改函数中,然后如果函数返回错误,则不替换原始对象。 The issue with this is that the JavaScript object is around 25 megabytes, so a copy of it would mean a significant increase in memory usage by the browser.这样做的问题是 JavaScript 对象大约为 25 兆字节,因此它的副本意味着浏览器的内存使用量显着增加。 So I would like to do this without creating a copy of the object.所以我想在不创建对象副本的情况下执行此操作。 I can just have the initial object be an input to the function and modify it recursively, but then if there is an error after some calls it could return a modified object when I don't want it to.我可以将初始对象作为函数的输入并递归修改它,但是如果在某些调用后出现错误,它可能会在我不希望它返回修改后的对象。

Would there be a way to do what I am trying to do?有没有办法做我想做的事? Keep track of the changes and easily undo them after an error, or something?跟踪更改并在出错后轻松撤消更改,或其他什么? Thanks.谢谢。

It is possible to create a transaction array that records each change made to the object and records enough data about the change such that it can be undone.可以创建一个事务数组,记录对对象所做的每个更改,并记录有关更改的足够数据,以便可以撤消。 This is not a trivial amount of work to do.这不是一项微不足道的工作。 It is somewhat similar to the undo capabilities in a word processor or spreadsheet for example.例如,它有点类似于文字处理器或电子表格中的撤消功能。 If you record the right level of information and keep it in order in an array, it should be possible to reverse all the changes.如果您记录正确级别的信息并将其按顺序排列在数组中,则应该可以逆转所有更改。 This is not rocket science, but it is a bit of code to write and test.这不是火箭科学,而是需要编写和测试的一些代码。

As mentioned in a comment, the larger question raised here is about a single 25MB object that has to be operated on by one function.正如评论中提到的,这里提出的更大的问题是关于必须由一个函数操作的单个 25MB 对象。 I'd personally wonder if you can break up the data into smaller pieces and be able to use smaller copies of things in order to not have to write this whole undo operation.我个人想知道您是否可以将数据分解成更小的部分并能够使用更小的副本,以便不必编写整个撤消操作。

Also, it's worth considering whether you can pre-flight enough of the operations to know ahead of time whether the code will fail before you've modified the object or not.此外,值得考虑是否可以预先执行足够多的操作,以便在修改对象之前提前知道代码是否会失败。 For example, I've used code before that runs all the same logic as the code that modifies the object, but it doesn't actually modify the object.例如,我之前使用过的代码运行与修改对象的代码完全相同的逻辑,但它实际上并没有修改对象。 This allows you to run a pre-flight of the entire operation and thus find out if anything fails some check before you've actually modified the object.这允许您运行整个操作的预检,从而在您实际修改对象之前找出是否有任何检查失败。 Written appropriately, you can use the same code for pre-flight as for actual modification with just an extra flag passed in. How feasible this is depends upon the exact nature of the modification operation, something you haven't disclosed.编写得当,您可以使用与实际修改相同的代码进行预检,只需传入一个额外的标志。这是否可行取决于修改操作的确切性质,您尚未披露。

Here's an example of such code that handles changes to a specific object property.下面是处理特定对象属性更改的此类代码示例。 This could be extended to include array manipulations too.这也可以扩展到包括数组操作。

Working demo: http://jsfiddle.net/jfriend00/ohqL0p06/工作演示: http : //jsfiddle.net/jfriend00/ohqL0p06/

Code:代码:

function TransactionSummary() {
    this.transactions = [];
}

TransactionSummary.prototype = {
    deleteProperty: function(parent, property) {
        this.rememberTransaction(parent, property, "delete", parent[property]);
        delete parent[property];
    },
    modifyProperty: function(parent, property, newVal) {
        this.rememberTransaction(parent, property, "modify", parent[property]);
        parent[property] = newVal;
    },
    addProperty: function(parent, property, newVal) {
        this.rememberTransaction(parent, property, "add");
        parent[property] = newVal;
    },
    rememberTransaction: function(parent, property, type, oldVal) {
        this.transactions.push({parent: parent, property: property, type: type, oldVal: oldVal});
    },
    undoTransactions: function() {
        var t;
        while (this.transactions.length) {
            t = this.transactions.pop();
            switch(t.type) {
                case "delete":
                case "modify":
                    t.parent[t.property] = t.oldVal;
                    break;
                case "add":
                    delete parent[property];
                    break;
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM