Creating a wait/sleep/delay Block

4,071 views
Skip to first unread message

Mike Mogenson

unread,
Oct 11, 2013, 1:11:44 PM10/11/13
to blo...@googlegroups.com
I would like to create a custom block to pause the execution of the user made, Blockly generated javascript for a specified amount of time.

Something like the image below.

One way to get this functionality on the javascript generator side is to create an inline blocking while loop such as:
var ms = 1000;
ms += new Date().getTime();
while (new Date() < ms) { }

I know this is a bad approach and it leads to the undesired behaviour of freezing the entire app until all the wait blocks have executed.   I haven't been able to think of a way to use setInterval() or setTimeout() to stop the lines of code beneath the block from evaluating.  Does anyone here have any suggestions?

Also, what are the timing options for Blockly?  I've looked a bit at the speedSlider in the Turtle demo app.  Is there a way to have a block request that the Blockly engine suspend execution of the script?

Thank you,
Mike Mogenson

Neil Fraser

unread,
Oct 11, 2013, 1:38:29 PM10/11/13
to blo...@googlegroups.com
It's impossible.  This isn't a Blockly issue, it is a JavaScript problem.  There is no way in JavaScript to write an in-line sleep statement.  The only option is to call setTimeout and call a function after a certain period (this block could be easily added to Blockly).  That said, there are some ways around it.

One way is to run the code in a web worker, a separate thread that does not block the browser's thread.  Then a busy loop will work fine.  The next big app we are building for Blockly will be using this technique.  Of course it will fail in IE 9 and earlier since there is no support for web workers.  Accessing the outside world also becomes interesting inside a web worker.

Another way is to run the user's code to completion without any delays, and every action adds to a log.  Then replay the actions in the log at whatever speed you desire.  This is how Turtle and Maze work.  All execution happens within a millisecond of hitting "Run Program", the subsequent apparent execution is totally fake.  Unfortunately, this technique gets trickier if the program has non-deterministic inputs, such as random numbers and user prompts.  One can get around this by running the program multiple times and caching previously-generated inputs.


--
You received this message because you are subscribed to the Google Groups "Blockly" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blockly+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



--
Neil Fraser
http://neil.fraser.name

Mike Mogenson

unread,
Oct 12, 2013, 9:44:25 PM10/12/13
to blo...@googlegroups.com, ro...@neil.fraser.name
Ok, I was afraid of this.

 I went ahead and created a setInterval block, pictured below.

The code this program generates is:
setInterval(function(){
alert('hi');
},3000);

However when this text is fed to the eval() statement nothing happens.  No error is thrown and nothing appears in the console log.  Any program without the Repeat Every N Seconds block works fine but nothing executes when that block is included.  Any thoughts as to what might be happening?

Thanks,
Mike 

Neil Fraser

unread,
Oct 13, 2013, 12:00:37 AM10/13/13
to blo...@googlegroups.com
That's odd.  Your code is correct and works perfectly when I eval it.  Are you using a non-browser environment (like node.js)?

Try adding an alert above and below the setInterval statement, just to verify that something is running.


--
You received this message because you are subscribed to the Google Groups "Blockly" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blockly+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Mike Mogenson

unread,
Oct 15, 2013, 11:15:02 AM10/15/13
to blo...@googlegroups.com, ro...@neil.fraser.name
My mistake.  I implemented the infinite loop trap incorrectly.

Michael Snowden

unread,
Jan 18, 2015, 3:46:28 AM1/18/15
to blo...@googlegroups.com
Here's a drop-in solution

// https://blockly-demo.appspot.com/static/demos/blockfactory/index.html#b99xcz
Blockly.Blocks['wait'] = {
  init
: function() {
   
this.setHelpUrl('http://www.example.com/');
   
this.setColour(60);
   
this.appendDummyInput()
       
.appendField("wait")
       
.appendField(new Blockly.FieldDropdown([["half a second", "500"], ["a second", "1000"], ["two seconds", "2000"], ["five seconds", "5000"]]), "DELAY");
   
this.setPreviousStatement(true, "null");
   
this.setNextStatement(true, "null");
   
this.setTooltip('');
 
}
};


Blockly.JavaScript['wait'] = function(block) {
 
var dropdown_delay = block.getFieldValue('DELAY');
 
// TODO: Assemble JavaScript into code variable.
 
var code = 'wait(' + dropdown_delay + ');\n';
 
return code;
};


var nextStepDelay = 10;


function wait(d) {
  nextStepDelay
= d;
}


function nextStep() {
 
if (myInterpreter.step()) {
   
var temp = nextStepDelay;
    nextStepDelay
= 10;
    window
.setTimeout(nextStep, temp);
 
}
}

and add this of course to your initApi function

var wrapper = function(d) {
 
return interpreter.createPrimitive(wait(d));
}
interpreter
.setProperty(scope, 'wait',
    interpreter
.createNativeFunction(wrapper));

Steve Nelson

unread,
Dec 22, 2016, 12:23:58 PM12/22/16
to Blockly
Michael, this all makes sense up to the "interpreter" section. I haven't gotten that far into blockly yet. Can you point me in the right direction to insert that code? Where is the "initApi" function?

Steve

picklesrus

unread,
Dec 22, 2016, 1:58:32 PM12/22/16
to Blockly
I'd start by looking at the following page and the demo it references.  I think they've been added since this thread began. https://developers.google.com/blockly/guides/app-integration/running-javascript#js_interpreter

Neil Fraser

unread,
Dec 22, 2016, 2:49:53 PM12/22/16
to blo...@googlegroups.com
Indeed, this thread predates the JS Interpreter.  With the interpreter, waiting becomes quite straightforward.

Send (awkwardly) from an Android phone.


--
You received this message because you are subscribed to the Google Groups "Blockly" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blockly+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Carlos Pereira

unread,
Dec 22, 2016, 2:53:44 PM12/22/16
to Blockly, ro...@neil.fraser.name
Is wait/sleep/delay now possible with the JS interpreter? Are there any examples?
To unsubscribe from this group and stop receiving emails from it, send an email to blockly+u...@googlegroups.com.

Andrew n marshall

unread,
Dec 22, 2016, 4:40:04 PM12/22/16
to blo...@googlegroups.com
In the same way one can timeout between interpreter.step() calls, you can schedule any other sort of loop or delay (e.g., checking on some paused state variable).

This is really just a generalization around this code:
    function nextStep() {
      if (myInterpreter.step()) {
        window.setTimeout(nextStep, 0);
      }
    }
    nextStep();
...discussed in the JS Interpreter docs.
To unsubscribe from this group and stop receiving emails from it, send an email to blockly+unsubscribe@googlegroups.com.

AMIT SINGH

unread,
Mar 24, 2017, 8:21:37 AM3/24/17
to Blockly
I have tried to below given wait to create and want a review whether it will work or not?

  Blockly.Blocks['wait_block'] = {
    init: function() {
      this.appendDummyInput()
          .appendField("delay")
          .appendField(new Blockly.FieldNumber(0, 0), "wait")
          .appendField("in secs");
      this.setPreviousStatement(true, null);
      this.setNextStatement(true, null);
      this.setColour(230);
      this.setTooltip('');
      this.setHelpUrl('');
    }
  };

  Blockly.JavaScript['wait_block'] = function(block) {
    var number_wait = block.getFieldValue('wait');
    // TODO: Assemble JavaScript into code variable.
    delays = Number(number_wait);
    function myFunction(){

    }
    var waiting = setTimeout(myFunction,delays);
    var code = document.getElementById('avatar').innerHTML = waiting;
    console.log(code);
    return code;
  };

Andrew n marshall

unread,
Mar 26, 2017, 4:57:59 AM3/26/17
to blo...@googlegroups.com

--

Toronto Productions

unread,
Mar 26, 2017, 9:45:31 AM3/26/17
to Blockly
Please do not post on year old topics.
To unsubscribe from this group and stop receiving emails from it, send an email to blockly+u...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages