Skip to main content
March 10, 2014
Question

Anything similar to javascript's setInterval in ExtendScript?

  • March 10, 2014
  • 4 replies
  • 9051 views

I need a way to poll my server for new jobs for the illustrator script to work on every few hours.

I tried with $.sleep(), but that is blocking, I need a non-blocking way to do this.

Any advice?

Thanks!

Kashmira

This topic has been closed for replies.

4 replies

Inventsable
Legend
February 3, 2019

Just to clarify, you can do this with a simple CEP panel. I don't know of a way to accomplish it with only .JSX, I tried the methods above as a new member and was discouraged since I couldn't get them to reliably work and others above say it's not possible with "JS" though it is as long as you're using CEP and running a simple CSInterface.evalScript function via setInterval.

Apparently Adobe forums doesn't accept text copied from VSCode. When I try to use the standard syntax highlighting feature here, it breaks and just gives me this:

// In CEP while using a Vue CDN:

Vue.component('timer', {

  data() {

   return {

   // Initialize data object for selection:

  selection: {

  timer: null,

  data: null,

  last: null,

  interval: 200,

  }

  }

  },

  mounted() {

   // When component is mounted, start a timer

   this.startTimer(this.selection)

  },

  methods: {

   startTimer(target) { target.timer = setInterval(this.selectionCheck, target.interval); },

   // The timer above runs the below code every 200ms

   selectionCheck() { csInterface.evalScript('scanSelection()', this.selectionRead); },

   // The check above returns a very simple value and calculation, only measuring for change with previous state.

   selectionRead(msg) {

   // If there is a change between this state and previous:

   if (this.selection.last !== msg) {

   // Then assign previous to this state

   this.selection.last = msg;

   // And now we know the state has been changed, use this as the trigger for a larger event.

  } else {

   // Nothing should happen, no change in selection or state.

  }

  }

  }

})

And on the JSX side, the function being called by the timer every 200ms:

function scanSelection() {

   var doc = app.activeDocument;

   var result = [];

   if (doc.pageItems.length) {

   for (var i = 0; i < doc.pageItems.length; i++) {

   var child = doc.pageItems;

   if (child.selected)

   result.push(i);

   }

   }

   if (doc.textFrames.length) {

   for (var i = 0; i < doc.textFrames.length; i++) {

   var child = doc.textFrames;

   if (child.selected)

   result.push(i);

   }

   }

   return result;

}

Which inevitably returns data to the selectionRead function in the original timer. Note that it doesn't have to be the selection count here, you can use a timer to measure any property accessible via scripting in this way, so you can easily create your own custom event listeners via running rudimentary checks.

ahmedk8610729
Participant
August 8, 2018

If you use $.sleep() in ExtendScript then it will block. If you want to create a feature like JavaScript setInterval then you will have to use onIdle event. It triggers on software IDLE time but it there is much more to it. You can check for system state in really short and long amounts of time. It will then return it to you and that is the interval.

Try the sample code:

function main() {
var myIdleTask = app.idleTasks.add({
name: “my_idle_task”,
sleep: 1000
});
var onIdleEventListener = myIdleTask.addEventListener(IdleEvent.ON_IDLE, onIdleEventHandler, false);
}
// SETINTERVAL DOSNT EXIST SO WE USE THE ONLY POSSIBLE WAY ONIDLE EVENT:
function onIdleEventHandler(myIdleEvent) {
var myTextFrames = app.activeDocument.pages.item(0).textFrames;
mimWinPnl.pgr.value +=1;
if(mimWinPnl.pgr.value > 99){ // progress bar value
//Delete idle task by setting its sleep time to zero.
myIdleEvent.parent.sleep = 0;
}
}

I hope it helps you !

Silly-V
Legend
August 8, 2018

That doesn't look like it's for Illustrator.

CarlosCanto
Community Expert
Community Expert
August 9, 2018

it is not...

...inDesign?

Matthias Guntrum
Participant
April 28, 2014

Hi,

I needed setInterval functionality and emulated it with the following snippet using app.scheduleTask();

Please note that i programmed with Adobe After Effects as my target application.

Gtlym = new Object();

Gtlym.CALL = new Object();

Gtlym.guid = function() {

     var s4 = function() { return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); };

     return s4() + s4() + s4() + s4()  + s4()  + s4() + s4() + s4();

}

Gtlym.setInterval = function(func,millis){

     this.guid = Gtlym.guid();

     Gtlym.CALL["interval_"+this.guid] = func;

     app.scheduleTask('Gtlym.CALL["interval_'+this.guid+'"]();',millis,true);

}

//Example:

Gtlym.setInterval(function(){/*your code here*/},1000);

Cheers,

Matthias

gentlymad.org - Matthias Guntrum

Inspiring
March 10, 2014

I have often wondered the same thing and researched it pretty extensively but to no avail. I am still wondering if there is some hack approach using dates, loops or practically anything to make a home brewed interval timer. But it seems like no. Even using Date for checking pretty much ends up emulating $sleep() from my tests. Why Adobe omitted common timers and intervals from the internal JS is beyond me, setInterval and setTimeout would be so useful, likewise the lack of mouse events, both those would open up entire new worlds of possibilities.

Here is a thread in the InDesign forum speaking of "app.scheduleTask" using Bridge: app.scheduleTask(script, delay [, repeat])

http://forums.adobe.com/message/3706907#3706907

I tried the "app.scheduleTask" approach and never got it working in Illustrator however. <-- I hope someone proves otherwise and says it is possible in Illustrator, please let me know if you do. Otherwise I don't think there are any solutions via JS. Maybe a timer in Applescript or VBScript however running in the background and working with Illustrator externally would be an alternative.

March 13, 2014

Ok, so here is what *might* work for what I need to do:

This wakes up every 5 seconds, checks if illustrator is busy, in which case it is still not done with the previous invocation of the illustrator script. If its idle, it runs the script. A bit roundabout, but at least something that works for me!

Thanks for pointing me in the right direction!

#target bridge

var myScript = 'CreateBridgeTalkMessage()';

app.scheduleTask(myScript, 50000, true);

function CreateBridgeTalkMessage() {

    var status = BridgeTalk.getStatus("illustrator");

 

    if(status == "IDLE" || status == 'ISNOTRUNNING')

    {

        var myScript = IllustratorScript.toString() + '\r';

        myScript += 'IllustratorScript();';

        var bt = new BridgeTalk();

        bt.target = "illustrator";

        bt.body = myScript;

        bt.send();

    }

}

function IllustratorScript() {   

   eval(readFile('C:\scripts\illustrator\batchFass.jsx'));

}

The readFile function is like this:

readFile: function(filename) {

        var file = new File(filename);

        file.open('r');

        return file.read();

}

March 13, 2014

Glad it was helpful to you and your efforts.

. What version of Illustrator are your using and are you calling that from Illustrator or from natively in the ExtendScript Toolkit?

I ask because I have CS5 and when I run a dumbed down version (seen below) in Illustrator I get "TypeError: app.scheduleTask is not a function", when I run it directly in the ESTK, I don't get the error but yet it does not yield anything either.

#target bridge

var num = 0;

var myScript = 'CreateBridgeTalkMessage()';

app.scheduleTask(myScript, 50000, true);

function CreateBridgeTalkMessage() {

    var status = BridgeTalk.getStatus("illustrator");

    if(status == "IDLE" || status == 'ISNOTRUNNING'){

        var bt = new BridgeTalk();

        bt.target = "illustrator";

        bt.body = "alert(\"Alert_\"+num);";

        bt.send();

    }

    num += 1;

}


I am using CS5 as well, and running it directly from ESTK. Have yet to try it from illustrator.

I tried your script, and I think there is some issue with the body you are sending. I tried only this:

bt.body = "alert('hello')";

and that worked.

I think the issue is the parameter "num"

I printed the one you were sending, and it was going out to illustrator as

alert("Alert_" + num);

Ilustrator does not know what "num" is, so I tried this:

bt.body = "alert('Alert_'" + num + ")";

It was sending the correct value for num, but illustrator still didn't like it.

So maybe that's something you can play around with?

-Kashmira