JS eval非常慢需要更好的方法

时间:2013-10-03 19:59:25

标签: javascript performance google-chrome loops webkit

我正在开发一个API,它将获取2个对象和一个表达式并执行false语句的过滤。返回第三个对象,该对象只包含表达式求值为true的数据集。

var obj1 = [
        {cn: 101, name: "AA", seq:1},
        {cn: 106, name: "BB", seq:2}
    ];

var obj2 = [
        { cid: 100, name: "XX", locator: "r" },
        { cid: 101, name: "AA", locator: "p"},
        { cid: 507, name: "TT", locator: "r"}
    ];

var output = MyClass.filter(obj1, obj2, "{source.cn}==={target.cid}"); 

obj1 is source object
obj2 is target object

expected output is: 
output = [
         { cid: 101, name: "AA", locator: "p"}
     ];

因为我的类是泛型类,所以它应该能够接受任何两个对象(任何结构和深度)并执行任何有效的javascript表达式。因此我找到了给定表达式的路径并准备了表达式列表。

source[0]["cn"]===target[0]["cid"]
source[0]["cn"]===target[1]["cid"]
source[0]["cn"]===target[2]["cid"]
source[1]["cn"]===target[0]["cid"]
source[1]["cn"]===target[1]["cid"]
source[1]["cn"]===target[2]["cid"]

获取表达式后,我会对每个表达式进行评估并过滤掉错误表达式。

eval(source[0]["cn"]===target[0]["cid"]) >>>>>EVAL RESULT>>>>> false
eval(source[0]["cn"]===target[1]["cid"]) >>>>>EVAL RESULT>>>>> true 
eval(source[0]["cn"]===target[2]["cid"]) >>>>>EVAL RESULT>>>>> false 
eval(source[1]["cn"]===target[0]["cid"]) >>>>>EVAL RESULT>>>>> false 
eval(source[1]["cn"]===target[1]["cid"]) >>>>>EVAL RESULT>>>>> false 
eval(source[1]["cn"]===target[2]["cid"]) >>>>>EVAL RESULT>>>>> false 

当这两个对象包含obj1 100个可能的路径和obj2 1000个可能的路径时,myclass会向eval生成100,000个语句。多数民众赞成它,它运行为众所周知的eval是缓慢但因为这些语句是字符串我不能把它放在“如果”

我尝试了一个测试代码,其中我在if语句中使用了语句,它非常非常快。我想使用if over eval。

我的测试代码如下:

var before = Date.now();
    var str, result, results = [], m, n;
    for(var i = 0, j=0; i <100000, j<100000; ++i,++j ){
        str = i + "===" + j;

        //eval(str)

        if(i === j) {
            result = true;
        } else {
            result = false;
        }           
    }

    var after = Date.now();
    console.log("Time: ", (after - before));

由于这些表达式可以是任何有效的JS表达式,所以我不能假设运算符。用户可以在表达式中自由使用任何类型的运算符(赋值,比较,算术,按位,逻辑,字符串或特殊运算符)。

例如:

"{source.cn}==={target.cid} && {target.name} != 'XX'"
or
"({source.cn}==={target.cid} || {source.cn}/100 === 1 )&& {target.name} != 'XX'"
or anything else.

我不想写自己的表达式解析器。

请提供帮助(不使用eval) 1.替代方法(但不是(new Function(expr)()) 2.使用“if”而不是“eval”的一些方法会使我的代码非常快。像上面的测试证明的那样。 3.任何其他方法,使其快速而不影响要求。 (是的,目标对象可能有多个匹配)

提前致谢。

1 个答案:

答案 0 :(得分:3)

首先可能不需要评估。

只需从传入字符串中切换

var output = MyClass.filter(obj1, obj2, "{source.cn}==={target.cid}"); 

使用功能

function comparator(source, target) { 
    return source.cn===target.cid 
}

var output = MyClass.filter(obj1, obj2, comparator); 

你的过滤器会很简单!

function filter(array1,array2, comparator) {
  var ret = []
  array1.forEach(function(source) {
     array2.forEach(function(target) {
        if (comparator(source,target)) ret.push(source)
     }
  })

  return ret
}

当然,如果考虑到效果,您将使用简单Array.forEach替换for