Data Source - Schema - Parse function error when creating new Function

6 posts, 0 answers
  1. Dominik
    Dominik avatar
    28 posts
    Member since:
    May 2015

    Posted 30 Jul 2015 Link to this post

    using the following constructor in the parse function throws an exception:

    new Function("args", body);

    "Uncaught SyntaxError: Unexpected identifierkendo.data.DataSource.schema.parse @ KendoWorklist?processId=1:257g.extend.success @ kendo?v=eOyB53xLlSdFHOrBbggvVxenL4FmfrA-viibHS3DbGs1:1g.extend.read.i._queueRequest.i.online.i.transport.read.success @ kendo?v=eOyB53xLlSdFHOrBbggvVxenL4FmfrA-viibHS3DbGs1:1vt.extend.read.i.success @ kendo?v=eOyB53xLlSdFHOrBbggvVxenL4FmfrA-viibHS3DbGs1:1i.Callbacks.a @ jquery?v=FVs3ACwOLIVInrAl5sdzR2jrCDmVOWFbZMY6g6Q0ulE1:1i.Callbacks.h.fireWith @ jquery?v=FVs3ACwOLIVInrAl5sdzR2jrCDmVOWFbZMY6g6Q0ulE1:1k @ jquery?v=FVs3ACwOLIVInrAl5sdzR2jrCDmVOWFbZMY6g6Q0ulE1:1i.ajaxTransport.send.u @ jquery?v=FVs3ACwOLIVInrAl5sdzR2jrCDmVOWFbZMY6g6Q0ulE1:1"

    why would the new Function constructor not work in the parse function?

  2. Dominik
    Dominik avatar
    28 posts
    Member since:
    May 2015

    Posted 31 Jul 2015 in reply to Dominik Link to this post

    the reason I want to use the new Function() constructor is because I send my data over normalized and the most efficient way to denormalize it is as follows:

     

    // My starting Normalized data
    var fields = ["name","age"];
    var data2 = [["John",20],["Tom",25]];
      
      
    // What I want the result to look like Denormalized
    var data1 = [{"name":"John", "age":20},{"name":"Tom", "age":25}];
      
      
    // Solution 1 O(N^2) --- this is slow
      
    var fields = ["name","age"];
    var data2 = [["John",20],["Tom",25]];
    var data1 = [];
    for(var i = 0; i < data2.length; i++){
        
    var temp = {};
        
    for(var y = 0; y < fields.length; y++){
           
    temp[fields[y]] = data2[i][y];
        
    }
        
    data1.push(temp);
    }
      
      
    // solution 2 O(N)
      
    var fields = ["name","age"];
    var data2 = [["John",20],["Tom",25]];
    var body = "";
      
    for(var i = 0; i < fields.length; i++){
        
    body += "this."+fields[i] +"=args["+i+"]; ";
    }
      
    var model = new Function("args",body);
      
    var data1 = [];
    for(var i = 0; i < data2.length; i++){
        
    var x = new model(data2[i]);
        
    data1.push(x);
    }

  3. Kendo UI is VS 2017 Ready
  4. Vasil
    Admin
    Vasil avatar
    1547 posts

    Posted 03 Aug 2015 Link to this post

    Hello Dominik,

    I think both solutions have the same complexity O(N*M);

    Where N is the count of the data.
    And M is the count of the fields.

    Additionally the const of the both approaches is pretty much the same.

    The difference is that in first approach you iterate the properties and build the object yourself. And in the second approach you pass some big constructor for this object, and the JS engine parses the values and then the browser do the same: iterate them and build the object. 

    If you perform some test, you will get very similar times in both large and small set of data. Here is some code based on yours:
    var fields = [];
    var data2 = [];
     
     
    for (var j = 0 ; j < 1000; j++) {
        fields.push("a" + j + "r" + Math.floor(Math.random() * 100));
    }
     
    for (var i = 0; i < 10000 ; i++) {
        var item = [];
        for (var j = 0 ; j < 100; j++) {
            item.push(Math.random());
        }
        data2.push(item);
    }
     
    var data1;
     
    function f1() {
        data1 = [];
     
        data1.length = data2.length;
        var temp;
     
        for (var i = 0; i < data2.length; i++) {
            temp = {};
            for (var y = 0; y < fields.length; y++) {
                temp[fields[y]] = data2[i][y];
            }
            data1.push(temp);
        }
    };
     
    function f2() {
        var body = "";
        for (var i = 0; i < fields.length; i++) {
            body += "this." + fields[i] + "=args[" + i + "]; ";
        }
     
        var model = new Function("args", body);
     
        data1 = [];
        data1.length = data2.length;
        for (var i = 0; i < data2.length; i++) {
     
            var x = new model(data2[i]);
            data1.push(x);
        }
    };

    The times that I get are 2.478s for the first function and 2.264 for the second for this very big set of data. For small set of data they work practically the same.

    From profiling in chrome it seems that the difference comes mainly from execution of the garbage collector more often in the first function.

    So you can use the working approach without any worries. I will additionally debug why the second one fails when passed as a parse function.

    Regards,
    Vasil
    Telerik
     
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
     
  5. Dominik
    Dominik avatar
    28 posts
    Member since:
    May 2015

    Posted 03 Aug 2015 in reply to Vasil Link to this post

    Thank you for looking into this for me!  Technically the first solution is (M*N) and the second solution is (M+N). For simplicity I used (N^2) and (N). But you're right, for small amounts of data there is little to no difference. 
  6. Dominik
    Dominik avatar
    28 posts
    Member since:
    May 2015

    Posted 03 Aug 2015 in reply to Vasil Link to this post

    also instead of concatenating with "+=" I should've used ".concat()"

    with this change f2() is much master than f1()

  7. Vasil
    Admin
    Vasil avatar
    1547 posts

    Posted 04 Aug 2015 Link to this post

    Hi Dominik,

    Interesting is that in Firefox (Nightly Builds) the solution 2 is actually slower than solution 1.

    Back to the original subject. I tried to get the same error as you, but in my case it is working correct, even with your original code.
    Here is testing example in our dojo:
    http://dojo.telerik.com/egIsA
    When I run it I get the alert displaying the name and age of the first record. And looking at the console, there is no exception like described.

    What I see here as the potential problem if the fields contains numbers without literal prefix.
    For example if the field is called "123" instead of "name". Then you will get exception when evaluating function like:
    "this.123 = something".
    however the first solution will work:
    this[123] = something

    Could you check  the example code above, and tell me what is different in your case. You can edit the example and write here the new link you get.

    Regards,
    Vasil
    Telerik
     
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
     
Back to Top
Kendo UI is VS 2017 Ready