5 Replies Latest reply on May 1, 2017 12:10 AM by talb37217143

    Improving javaScript performance

    talb37217143 Level 1

      Hi all,

       

      I'm running a script which moves a bunch of elements around inside artboards.

       

      the script runs pretty slow when the number of artboards (and artboard sub layers) increases - obviously

       

      I was wondering what can I do to improve the performance?

       

      from what I gathered from scouring the forum:

       

      1. use action descriptor and avoid photoshop DOM when possible

      2. run app.togglePalettes() before the script

      3. set script to accelerated mode (what ever that means )

       

      are there any other ways to increase performance? maybe turn off the screen updates until the script is finished?

      b.t.w - if there is a possibility of turning of the screen updates - is it possible to turn on a progress bar or is it all or nothing?

       

       

       

      thanks in advance!!

        • 1. Re: Improving javaScript performance
          Jarda Bereza Level 4

          Not using Photoshop DOM is very good idea.

           

          I have good experience with:

          1) Use references properly. Sometimes you don't need use targetEnum. So you don't need set active layer and then restore selected layer. You can save 20-40ms per layer. I changed my method from selecting layers and then deleting them at once. Now I am deleting layer without selecting them. Deleting without selection si faster then selection itself. In case of 1000 layers I improved script duration from 213 seconds to 121 seconds.

          2) Sometimes you can put list references to layers into action reference if you want do same task with multiple layers. This should be fastest possible task with multiple layers.

          function hideMulti(list){ 
              var idHd = charIDToTypeID( "Hd  " );
                  var desc19 = new ActionDescriptor();
                  var idnull = charIDToTypeID( "null" );
                      var list9 = new ActionList();
                      for(var i = 0, len = list.length; i < len; i++){
                          var ref = new ActionReference();
                          //some alternatives
                          //layerRef.putIdentifier( cTID('Lyr '), list[i] );
                          //layerRef.putName( charIDToTypeID( "Lyr " ), "Layer 7" );
                          ref.putIndex( charIDToTypeID('Lyr '), list[i] );
                          list9.putReference( ref );
                      }
                  desc19.putList( idnull, list9 );
              executeAction( idHd, desc19, DialogModes.NO );
          }
          

           

          3) Photoshop UI is usually frozen while script runing. You can force UI redraw.

          4) If you want move/transform text layer, you don't need use classic transformation. With executeActionGet you can get textKey and change some properties inside. Like textClickPoint and then you put modified descriptor inside executeAction. With modifing textClickPoint you can move text layer without selecting it. You also can set 2D transformation matrix inside text layer (rotate/skew/scale)

          5) Since CC2015 you can use built-in progressbar function. Show text messages about progress inside this dialog and have possibility to cancel anytime. If you update progressbar it takes a little time. So don't update progressbar too fast.

          6) If you want read properties about layers you can be more specific in reference. Example:

          $.hiresTimer;
          var ref = new ActionReference(); 
          ref.putProperty(charIDToTypeID( "Prpr" ), stringIDToTypeID("height"));
          ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );  
          var desc = executeActionGet(ref); 
          var height = desc.getDouble(stringIDToTypeID ("height"))    
          alert("Property defined in reference.\nDocument height:"+height+"\nDuration: " + $.hiresTimer + "μs");
          
          
          
          $.hiresTimer;
          var ref = new ActionReference(); 
          ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );  
          var desc = executeActionGet(ref); 
          var height = desc.getDouble(stringIDToTypeID ("height"))    
          alert("Property NOT defined in reference.\nDocument height:"+height+"\nDuration: " + $.hiresTimer + "μs");
          

           

          On my PC I can get document height in 0,13ms if I define property in reference. Or in 168ms if I don't.

          This is similar with layers.

          7) try reduce the number of steps. Photoshop should do only necessarily things.

          8) avoid DOM recursion

          9) store stringID/charID in constants if you use this conversion very offten

          • 2. Re: Improving javaScript performance
            talb37217143 Level 1

            thank you for the detailed response!

             

            a few follow up questions if you will:

             

            1. If I understand correctly, whenever I see "charIDToTypeID("Trgt")" in a script it means that the reference is the selected/active layer. so if i replace it with "ref.putIdentifier(charIDToTypeID('Lyr '), _layerID)" that means that the reference is pointed at the layer with that ID right? and then I save the time wasted on setting active layer?

             

            2. If I use app.activeDocument.layers alot - is it a good idea to cache the layer list as a global variable?

             

            thanks again!

            • 3. Re: Improving javaScript performance
              Jarda Bereza Level 4

              ad 1) correct - "Trgt" is also used for active document, paths, channels ect. In this case you would need other class then "Lyr "

              ad 2) not much. You can extract some properties and these properties you can put inside your new object without functions and other balast. For examle you could assign all selected layersID or names into simple array. And then work with array.

               

              If you do:

              var layer = app.activeDocument.activeLayer;

              then layer is reference. It's only shortcut. There will be a bit time saving because JS don't need search for reference inside app and inside activeDocument but difference wouldn't be huge.

              • 4. Re: Improving javaScript performance
                Jarda Bereza Level 4

                I updated my script "Delete all empty layers faster" here Magic scripts for Photoshop

                It uses AM code a lot instead DOM and I am not using recursion. It has progressbar and you can cancel script if you see it. But if script duration is under ~10s you don't see it. And I don't see progressbar even if document has 2000 layers.

                 

                I am using something like custom layers model with needed properties.

                 

                If you go in PS menu in: File > Scripts > Delete All Empty Layer ...you can compare it with script from Adobe. It uses DOM and recursion. Try document with 500 layers and higher.

                 

                I did some measurement and my script is 40-50× faster :-)

                 

                 

                Anyway I am interested if I can be more specific in reference. I would like to specify property in property which I want.

                • 5. Re: Improving javaScript performance
                  talb37217143 Level 1

                  Gotcha,

                   

                  thank you!