Javascript: How to wait for eval-function?

Viewed 670

I am working on a project that paints Objects from Blockly Code Blocks. Therefore a code string is generated that is evaluated in the function below. In the code run with the eval function, all created objects are stored in an array (objects). My problem is that the code is not completely evaluated before alert(objects.length) can work with the updated objects array (so it alerts zero as I have reset the array before). So the alert should wait for the eval function. Can you help me how to solve this problem?

function paintFromCode() {
   slideTo('konva_box');
   setTimeout(function(){
       deleteObjects();
       let code = Blockly.JavaScript.workspaceToCode(workspace);
       try {
          code = "let t = 0;" + code;
          eval(code);
       } catch (e) {
          alert(e);
       }
       layer.add(pospanel);
       alert(objects.length);
   }, 1000);
}

Part of the function where the code is created:

let code = "setTimeout( function() {" +
    "objects['" + text_identifier.toUpperCase() + "'] = new Konva.Circle({x: 50, y: 100, radius: 50, fill: '#00ff00'});" +
    "layer.add(objects['" + text_identifier.toUpperCase() + "']);" +
    "layer.draw();" +
    "}, speed * t);" + 
    "t = t + 1;";
return code;
3 Answers

The way you have written the code above, it seems you control layer. Running the code block has a call to layer.draw() at the end. You can redefine draw to call your alert statement.

// store original draw function
const orginalDraw = layer.draw;
layer.draw = function() {
   originalDraw();
   alert('draw has just been called');
}
try {
  code = "let t = 0;" + code;
  eval(code);
} catch (e) { alert(e); }
    

EDIT My initial response was unnecessarily complex... With the assumption that the setTimeout is occurring within the Blockly Code Blocks returned code string, suggest intercepting the setTimeout function, and inserting the post-timeout processing there. (Another alternative is to search and replace entries of setTimeout within the Blockly Code Blocks code string, replacing with a similar custom setTimeout function that performs post-timeout processing also.)

// Simulate ==> let code = Blockly.JavaScript.workspaceToCode(workspace);
// with an embedded setTimeout in the code to be eval-ed.
let code = `
  setTimeout( () => alert('Blocky!'), 2000);
`;

// Define the custom function to run once the setTimeout is complete.
var a = 0;
function postTimeout( x ) {
  console.log( a );
  a = x;
  console.log( a );
  alert( a );
}

// Finally, execute the "Blocky" code. But first, intercept the setTimeout
// function and afterwards reset it.  Alternatively, one can search and
// replace 'setTimeout(' in the Blocky code, replacing with similar 
// intercepting function.
const stf = setTimeout;
setTimeout = function(f,ms) {
  return stf( () => { f(); postTimeout( 42 ) }, ms)
};
  
eval( code );

setTimeout = stf;

Upon running this snippet, in 2 seconds the alert('Blocky!') will fire representing the Blocky code with the setTimeout function, and then immediately afterwards, the custom postTimeout function will fire which simulates the

layer.add(pospanel);
alert(objects.length);

in the question.

I have included var a as a test of reaching beyond the scope of the "Blocky" javascript within the code variable...

i had same problem and here is how i handled it

try { 
       eval("(async () => {"+code+"})()");

        }
catch (e) {
                       alert(e);
                          }

and code was splitted in myArr1 by function and after each function i added

   let wait='); await this.waitfunction(500);';
                         for (var i=0; i<myArr1.length-1;i++){

                        let tex=
                      myArr1[i].concat(wait);
                  b[i]=tex;
                  

                  }

here is my waitfunction():

waitfunction(ms){

return new Promise(resolve => {
  setTimeout(()=>resolve(''),ms)
   });
}

i know that was long but it works

Related