Javascript solves the memory leak problem caused by a large number of calls to eval

1. The problem arises

I am writing a software where users can customize the code logic. For a certain code block, the javascript code (string) written by the user needs to be executed, and eval is naturally used. For this I declare a processing class, the main logic functions are as follows.

export default class DBCCondition extends ConditionBase {
    constructor(past_results, cdata) {
        this.cdata = cdata;
    }
    //--过滤组合
    filter(result) {
        let isok =true;
        eval(this.cdata.functions.filter);
        return isok;
    }
};

Insert picture description here
For this.cdata.functions.filterthis is a string code written by the user, isokmodify the attribute according to the value of result .

//--filter的一个值如下
filter:"isok = result.getBlueSum() > 10"

In the actual environment, the DBCConditionclass object function filterwill be called millions of times. For eval, I found that every time the browser is called, a section of memory is allocated to execute internal code. Naturally, with millions of eval calls, 2 G of browser memory will be consumed instantly. Caused the process to freeze, unable to carry out my next processing logic.

2. Explore

I checked a lot of information about eval on the Internet and searched for a long time, but found that there is no article about solving the memory leak caused by a large number of calls to eval. It suddenly occurred to me, why not define the user-defined part as a function, so that when the DBCConditionclass object is initialized, the function is solved Function? In this way, eval is executed only once.

Try 1

Modify the DBCConditionclass:

export default class DBCCondition extends ConditionBase {
    constructor(past_results, cdata) {
        this.cdata = cdata;
        this._inner_filter = funcion(result){
			let isok =true;
            eval(this.cdata.functions.filter);
            return isok;
		}
    }
    //--过滤组合
    filter(result) {
        return this._inner_filter(result);
    }
};

After reading it, I found out that it didn't work. _inner_filterThe eval inside will still be executed a million times, and the browser will freeze. collapse.

Try 2

Check the eval grammar and find that you can pass a js function so that it can be returned directly Function:

var fn = eval(function(){
	console.log("excuted");
})

fn();// 输出"excuted"

But I can't let users change my code. What the user passes is always a string. I am excited to try with string functions:

var fn = eval("function(){console.log('excuted');}");

Insert picture description here

Sure enough, the grammar couldn't make it through.

Try 3

Continue reading the information and found that the eval function can be windowexecuted in the global domain. In the way of trying, I typed out the following code in the console:

var fn = eval("window.__g__= function(){console.log('excuted');}");

No error was reported! This is indeed an executable js statement, and it runs successfully. View the value of fn:
Insert picture description here

ok~ I successfully converted a string into an Functionobject!

It's easy now. Modify the DBCConditionclass:

export default class DBCCondition extends ConditionBase {
    constructor(past_results, cdata) {
        this.cdata = cdata;
        this._inner_filter = eval(`window.__temp__var__=${this.cdata.functions.filter}`)
    }
    //--过滤组合
    filter(result) {
        return this._inner_filter(result);
    }
};

Of course, you have to modify the user-defined string function, change the original direct operation isoklogic to return, and then pass in the resultparameters

//--filter的一个值如下
filter:"function(result){return result.getBlueSum() > 10}"

Compile and run. everything is normal.

3. Conclusion

eval is not recommended. It is said on the Internet that there are other solutions to replace 99.99% of the cases with eval. But mine seems to be 0.01%. If any blogger thinks I can solve this situation without using eval, please comment~

Guess you like

Origin blog.csdn.net/qq_29722281/article/details/91578796