Synchronously perform executeAsModal on every layer from activeLayers array

Hi,
Is there a way to synchronously perform executeAsModal on every selected layer from activeLayers array? I tried to await executeAsModal promise and even then it breaks that synchronous operation and gives incorrect result (some transformations are applied before others and sometimes multiple times in a row before others are applied).

Here is some sample to code for what I want to achieve:

const handleExecution = async () => {
    // Check if there is any active document before executing the function
    if (!app.activeDocument) {
      await app.showAlert("No active document!");
      return;
    }
    const originalLayers = app.activeDocument.activeLayers;
    originalLayers.forEach(async (layer) => {
      await transformLayer(layer)
      });
    });
  };

And the code for transformLayer function:

import { app, constants, core } from "photoshop";
import { Layer } from "photoshop/dom/Layer";

export const transformLayer= async (
  layer: Layer
) => {
  try {
    await core.executeAsModal(
      async () => {
        const newLayer = await layer.duplicate();
        newLayer .selected = true;
        newLayer .name = "New layer";
        await newLayer.scale(100, 50, constants.AnchorPosition.BOTTOMCENTER);
        newLayer.opacity = 50;
        newLayer.move(layer, constants.ElementPlacement.PLACEAFTER);
        newLayer.link(layer);
        newLayer.selected = false;
        layer.selected = true;
      },
      { commandName: "Creating a transformed layer..." }
    );
  } catch (e) {
    console.log(e);
  }
};

Or should I have multiple executeAsModal for every operation on the layer or is it fine to group them all into a single executeAsModal?

Wrap everything in execModal. You can also have execModal inside execModal. So I think this should be enough:

await core.executeAsModal(
  handleExecution,
  { commandName: "Creating a transformed layer..." }
)

I tried it and it didn’t help. It turns out that some operations are still performed before others. In the end, I would like to have it like this:

  1. User selects for example 2 layers.
  2. Transformations applied to layer 1. Done.
  3. Transformations applied to layer 2. Done.

So it goes exactly in this order. And right now it does it like this:

  1. User selects 2 layers.
  2. Transformations applied to layer 1 and layer 2 simultaneously (this is incorrect because some transformations are applied twice or more times in a row depending on the number of selected layers).

Ah… Don’t use forEach with async/await. Switch to for

Yep. That worked! Thanks Karmalakas

And now I just read that forEach expects only synchronous functions. It was a small note on the official MDN page. I will keep this in mind for future use cases :slight_smile: Thanks again

I would recommend you to wrap the whole loop into executeAsModal if that loop has to run uninterrupted by other plugins or by the user. Also, I think you will get some performance gain and better possibility to report progress into the progress bar, and also better history suspension.

Alright. Thanks. I just did that and I see some performance improvements. I also suspended history into a single state.

1 Like

Exactly what I suggested here :slight_smile: