HTML Panels Tips #15 Asynchronous vs. Synchronous

Davide Barranca —  — 3 Comments

Today’s tip focuses on the Asynchronous nature of CSInterface.evalScript() calls, and on ways to make it work in a synchronous fashion.

Synchronous vs. Asynchronous

Quoting StackOverflow:

When you execute something synchronously, you wait for it to finish before moving on to another task.
When you execute something asynchronously, you can move on to another task before it finishes.

Or visually:



Back in Flash days evalScript was synchronous, now in HTML land is asynchronous:

Async example

Remember that evalScript function takes two params:

  • The ExtendScript code to run.
  • A callback function, which in turn takes as a param the returned value from the ExtendScript call.

The default behavior is as follows.

In the above example the app.documents.length statement is executed and directly returned – the number of currently opened documents in Photoshop is passed to the callback, which assignes it to the numberOfDocuments variable.

The alert says “undefined” because of the asynchronous nature of evalScript: line #4 executes, then the interpreter goes ahead to line #8 not waiting for the ExtendScript to return (in this example, a single line of code, but in real world a long chain of functions that trigger usually time consuming Photoshop operations) so when alert(numberOfDocuments) is called, numberOfDocuments is still undefined.

So to speak, it is like asking your partner to do the shopping then, as soon as (s)he goes out, open the fridge and say “rats, it’s empty!”

Sync workarounds

There are few different ways to mimic a synchronous behavior

1. Set a Timeout

The easiest way is to just wait for your partner to get back from the store:

Although, it’s not ideal. You might not know in advance how long to wait – it depends of the kind of ExtendScript task you’re executing.

2. Nest code in Callbacks

If the alert is moved within the callback it works properly:

Of course this can lead to the so-called callback hell – nesting evalScript calls one inside another, like:

Yet if you’ve not fancy needs, it works.

3. Event driven callbacks

This method is supported only from CEP 5.2 onwards.
You can implement custom Events via PlugPlugExternalObject, that are dispatched by ExtendScript and listened from JS.
I’ve put the ExtendScript code in its own JSX file:

Then in the JS you set up a listener, which is the one who fires the alert();

Mind you, as far as other devs such as Kris Coppieters have supposed, “even if you manage to make multiple JSX calls from different parts of your JS, probably you can’t run multiple ExtendScripts concurrently“.


I’d like to thank Zihong Chen and Ten from Adobe and the others who’ve helped shedding some light upon this topic in the forums.

Print Friendly

3 responses to HTML Panels Tips #15 Asynchronous vs. Synchronous

  1. The event driven callbacks method is interesting, but seems far too complicated for most use cases. Personally I like using promise. Adobe’s extension platform doesn’t yet support promises natively, so I include this polyfill to add support. Then I create an “evalScript” function that returns a promise.

    This makes the code much simpler and more readable. And since promises are chainable, this makes it easy to chain commands together without nesting callbacks in callbacks.

    • Great suggestion James, thank you!
      One thing, though – shouldn’t the evalScript be as follows?


  2. As a reminder to my future self and all those who might be interested, the syntax for promises using the Q library is as follows:

Leave a Reply

Text formatting is available via select .

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">