Anything similar to javascript's setInterval in ExtendScript?

Copy link to clipboard
Copied
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
Explore related tutorials & articles
Copy link to clipboard
Copied
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.

Copy link to clipboard
Copied
Thank you! I will try using scheduleTask and update this thread on my findings.

Copy link to clipboard
Copied
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();
}
Copy link to clipboard
Copied
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;
}

Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
Thanks for the feedback. What a shame however that it requires 3 applications (Illustrator/ESTK/Bridge) to all be running just to invoke and use a simple interval. I think using Applescript/VBscript would be less overhead and maybe a cleaner approach myself.
Copy link to clipboard
Copied
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
Copy link to clipboard
Copied
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 !
Copy link to clipboard
Copied
That doesn't look like it's for Illustrator.
Copy link to clipboard
Copied
it is not...
...inDesign?
Copy link to clipboard
Copied
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:
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.

