Is it only me that thinks the CS5 scripts runs painfully slow?
These few lines takes over 1 minute to execute.
for (n=0; n<app.activeDocument.layerSets.length; n++) {
app.activeDocument.layerSets[n].visible = false;
}
The number of layerSets are 20.
I'm running the CS5.1 64bit version on a Vista Home Premium system, AMD Athlon 64 X2 Dual Core 5200+ with 8GB RAM.
I tried to Export the script as a .JSXBIN but it still takes over 1 minute. CPU usage for CS5.1 goes from 3% to 57% when the CS5.1 is running the .JSXBIN script.
There must be something wrong here, how can I speed up the scripts?
// Thanks
* EDIT *
It seems like CS5's own DOM implementation is the problem here. The script speeded up more than twice by reading DOM related values into local variables.
var LayerCount = app.activeDocument.layerSets.length;
var LayerRoot = app.activeDocument.layerSets;
for (n=0; n<LayerCount; n++) {
LayerRoot[n].visible = false;
}
...but still, it far to much time to just change a property in 20 objects. Any help with optimizing would be appreciated :)
The only thing I can think of is try try to loop through the individual layers in app.activeDocument.layers which contains all the layers and groups. When you do this you'll notice that grouped layers will still retain their original visible property but are hidden because their parent group is hidden.
#target photoshop
var myLayers = app.activeDocument.layers;
var myLayersLength = myLayers.length;
for (var i=0; i<myLayersLength; i++) {
myLayers[i].visible = false;
}
EDIT: So I tested this solution on a 400mb file with 50 layers and it worked in seriously less than a second. Are you sure the problem is with Photoshop?
If you have to iterate through every single layer and child-layer individually to perform an action you can do it recursively:
#target photoshop
var doc = app.activeDocument;
findLayers(doc);
function findLayers(set) {
for (var i=0; i<set.layerSets.length; i++) {
//recursive call
findLayers(set.layerSets[i]);
//iterate sub-layers and hide
for (var j=0; j<set.layerSets[i].layers.length; j++) {
set.layerSets[i].layers[j].visible = false;
}
}
//hide top-level layers
for (var l=0; l<set.layers.length; l++) {
set.layers[l].visible = false;
}
}
This takes a bit longer, ~20 seconds on my machine, but it will hit every single layer in a document.
NOTE: I also tested your original scripts from the question and they don't work on un-grouped layers because you're iterating through document.layerSets instead of document.layers
Have a look at this ps-scripts iteration over layers is slow - explanation
Which may be able to help you as well.
Related
I have a question over at collision-detection about a similar issue, but it's not exactly the same. I had an issue with a new game project (I'm trying to learn more about HTML5 Canvases and Socket.io) in which my collisions weren't working. I thought that my issue was centered on collisions, but now I'm starting to think something different. The reason I have a different issue posted here at the for-loop area is because I'm not sure if my issue is for-loop related or collision-detection related. Either way, I'd be happy to take one of my questions down.
This code is looping every frame to get the active positions of bullets and ships. If the bullet touches the ship, it'll be removed and some health points will be removed from the ship.
Tutorial I was using: http://jlongster.com/Making-Sprite-based-Games-with-Canvas
That aside, here's my checkCollisions code. It seems that the collision function is working, because when I started to log all the positions every time we had an iteration, it seemed that the position of my object was changing every single time. Is this one of those for-loop issues where I'm going to need a callback?
Thank you so much in advance for all your help. I'll be sure to upvote/select every response that helps out! :)
SOLVED! Turns out one of my arrays wasn't being passed in correctly. I'd like to thank you guys for telling me to always split it into multiple functions, that really helped me figure that one out!
// Let's start out here: I have a players[] array
//that's essentially a list of all players on the server
// and their positions. I omitted server connection functionality since that's not my error
// source.
function checkCollisions() {
for (var i = 0; i < players.length; i++) { // Iterating through all players
var pos = [players[i].posX, players[i].posY];
var size = [SHIP_WIDTH, SHIP_HEIGHT]; // This is the size of each player, it's a ship game. So these are constants.
if (players[i].userId != PLAYER.userId) { // Each player has a userId object, this is just doublechecking if we're not uselessly iterating
for (var j = 0; j < bullets.length; j++) { // We're now looping through bullets, an array of all the bullets being shot by players
var pos2 = bullets[j].pos;
var size2 = BULLET_SIZE;
var sender = bullets[j].sender;
if (boxCollides(pos, size, pos2, size2)) { // Collision code
if (sender != players[i].userId) {
bullets.splice(j, 1);
i--; // Tried here with j--, and by removing the entire line. Unfortunately it doesn't work :(
break;
}
}
}
}
}
}
Have you tried using console.log to see where the program is breaking? This might help you determine if there are multiple bugs or if it's just this one. If there's something wrong in a previous statement, you may not know it if you've fixed the i-- / j-- ...?
Edit: AH I see that you've fixed things, after I'd posted this. Well congrats and good job!
I have an array with 2000 arrays which each have 2000 values (to stock a 2000x2000 image) in javascript in an HTA. I have this code to test how many "blue" values there are in the array (the array's name is image):
var bluePixels = 0;
for(i = 0; i < image.length; i++){
for(j = 0; j < image[i].length; j++){
if(image[i][j] == "blue"){bluePixels = bluePixels + 1}
}
}
alert(bluePixels);
The problem is that it shows a message where it says something like "Stop execution of this script? A script on this page is slowing down Internet Explorer. If it continues, your computer might not answer." (I'm not sure of the exact words because my computer is in French) and then, if I click on "no", it does the alert(bluePixels) like it should but if I push on "yes" it doesn't. How can I block this message? (I know that there are workarounds like telling the user in the beginning to press "no" but I want a real solution)
For IE versions 4 to 8, you can do this in the registry. Open the following key in Regedit: HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Styles. If this key doesn't exist, create it. In this key, create a DWORD value called MaxScriptStatements and give it the value 0xFFFFFFFF (don't worry if the value changes automatically when you click on OK, that's normal).
You can program JavaScript to do this automatically:
var ws = new ActiveXObject("WScript.Shell");
ws.RegWrite("HKEY_CURRENT_USER\\Software\\Microsoft\\Internet Explorer\\Styles\\","");
ws.RegWrite("HKEY_CURRENT_USER\\Software\\Microsoft\\Internet Explorer\\Styles\\MaxScriptStatements",1107296255,"REG_DWORD");
Seems like you have an answer here
From the answer:
"The only way to solve the problem for all users that might be viewing your page is to break up the number of iterations your loop performs using timers, or refactor your code so that it doesn't need to process as many instructions."
So the first approach can be attained using a timeout for each such large iteration.
You need to split the 2000x2000 for-loop's up in smaller pieces of code, eg threads or processes, so the browsers maximum execution time not is becoming exhausted. Here the image array is parsed for one row at a time, controlled by a timer :
var bluePixels = 0,
timer,
i = 0;
function countBluePixels() {
for (var j = 0; j < image[i].length; j++){
if (image[i][j] == "blue") {
bluePixels = bluePixels + 1;
}
}
i=i+1;
if (i>image.length) {
clearInterval(timer);
alert(bluePixels);
}
}
timer = window.setInterval(countBluePixels, 0);
The code is the same, just splitted up in 2000 processes instead of 1.
Javascript is everywhere and to my mind is constantly gaining importance. Most programmers would agree that while Javascript itself is ugly, its "territory" sure is impressive. With the capabilities of HTML5 and the speed of modern browsers deploying an application via Javascript is an interesting option: It's probably as cross-platform as you can get.
The natural result are cross compilers. The predominant is probably GWT but there are several other options out there. My favourite is Coffeescript since it adds only a thin layer over Javascript and is much more "lightweight" than for example GWT.
There's just one thing that has been bugging me: Although my project is rather small performance has always been an important topic. Here's a quote
The GWT SDK provides a set of core Java APIs and Widgets. These allow
you to write AJAX applications in Java and then compile the source to
highly optimized JavaScript
Is Coffeescript optimized, too? Since Coffeescript seems to make heavy use of non-common Javascript functionality I'm worried how their performance compares.
Have you experience with Coffeescript related speed issues ?
Do you know a good benchmark comparison ?
Apologies for resurrecting an old topic but it was concerning me too. I decided to perform a little test and one of the simplest performance tests I know is to write consecutive values to an array, memory is consumed in a familiar manner as the array grows and 'for' loops are common enough in real life to be considered relevant.
After a couple of red herrings I find coffeescript's simplest method is:
newway = -> [0..1000000]
# simpler and quicker than the example from http://coffeescript.org/#loops
# countdown = (num for num in [10..1])
This uses a closure and returns the array as the result. My equivalent is this:
function oldway()
{
var a = [];
for (var i = 0; i <= 1000000; i++)
a[i] = i;
return a;
}
As you can see the result is the same and it grows an array in a similar way too. Next I profiled in chrome 100 times each and averaged.
newway() | 78.5ms
oldway() | 49.9ms
Coffeescript is 78% slower. I refute that "the CoffeeScript you write ends up running as fast as (and often faster than) the JS you would have written" (Jeremy Ashkenas)
Addendum: I was also suspicious of the popular belief that "there is always a one to one equivalent in JS". I tried to recreate my own code with this:
badway = ->
a = []
for i in [1..1000000]
a[i] = i
return a
Despite the similarity it still proved 7% slower because it adds extra checks for direction (increment or decrement) which means it is not a straight translation.
This is all quite intersting and there is one truth, coffee script cannot work faster than fully optimized javascript.
That said, since coffee script is generating javascript. There are ways to make it worth it. Sadly, it doesn't seem to be the case yet.
Lets take the example:
new_way = -> [0..1000000]
new_way()
It compiles to this with coffee script 1.6.2
// Generated by CoffeeScript 1.6.2
(function() {
var new_way;
new_way = function() {
var _i, _results;
return (function() {
_results = [];
for (_i = 0; _i <= 1000000; _i++){ _results.push(_i); }
return _results;
}).apply(this);
};
new_way();
}).call(this);
And the code provided by clockworkgeek is
function oldway()
{
var a = [];
for (var i = 0; i <= 1000000; i++)
a[i] = i;
return a;
}
oldway()
But since the coffee script hides the function inside a scope, we should do that for javascript too. We don't want to polute window right?
(function() {
function oldway()
{
var a = [];
for (var i = 0; i <= 1000000; i++)
a[i] = i;
return a;
}
oldway()
}).call(this);
So here we have code that does the same thing actually. And then we'd like to actually test both versions a couple of time.
Coffee script
for i in [0..100]
new_way = -> [0..1000000]
new_way()
Generated JS, and you may ask yourself what is going on there??? It's creating i and _i for whatever reason. It's clear to me from these two, only one is needed.
// Generated by CoffeeScript 1.6.2
(function() {
var i, new_way, _i;
for (i = _i = 0; _i <= 100; i = ++_i) {
new_way = function() {
var _j, _results;
return (function() {
_results = [];
for (_j = 0; _j <= 1000000; _j++){ _results.push(_j); }
return _results;
}).apply(this);
};
new_way();
}
}).call(this);
So now we're going to update our Javascript.
(function() {
function oldway()
{
var a = [];
for (var i = 0; i <= 1000000; i++)
a[i] = i;
return a;
}
var _i;
for(_i=0; _i <= 100; ++_i) {
oldway()
}
}).call(this);
So the results:
time coffee test.coffee
real 0m5.647s
user 0m0.016s
sys 0m0.076s
time node test.js
real 0m5.479s
user 0m0.000s
sys 0m0.000s
The js takes
time node test2.js
real 0m5.904s
user 0m0.000s
sys 0m0.000s
So you might ask yourself... what the hell coffee script is faster??? and then you look at the code and ask yourself... so let's try to fix that!
(function() {
function oldway()
{
var a = [];
for (var i = 0; i <= 1000000; i++)
a.push(i);
return a;
}
var _i;
for(_i=0; _i <= 100; ++_i) {
oldway()
}
}).call(this);
We'll then do a small fix to the JS script and change a[i] = i to a.push(i) And then lets try again...and then BOOM
time node test2.js
real 0m5.330s
user 0m0.000s
sys 0m0.000s
This small change made it faster than our CoffeeScript Now lets look at the generated CoffeeScript... and remove those double variables...
to this:
// Generated by CoffeeScript 1.6.2
(function() {
var i, new_way;
for (i = 0; i <= 100; ++i) {
new_way = function() {
var _j, _results;
return (function() {
_results = [];
for (_j = 0; _j <= 1000000; _j++){ _results.push(_j); }
return _results;
}).apply(this);
};
new_way();
}
}).call(this);
and BOOM
time node test.js
real 0m5.373s
user 0m0.000s
sys 0m0.000s
Well what I'm trying to say is that there are great benefits to use a higher language. The generated CoffeeScript wasn't optimized. But wasn't that far from the pure js code. The code optimization that clockworkgeek tried to use with using index directly instead of push actually seemed to backfire and worked slowlier than the generated coffeescript.
The truth it that such kind of optimization could be hard to find and fix. On the other side, from version to version, coffeescript could generate optimized js code for current browser or interpreters. The CoffeeScript would remain unchanged but could be generated again to speedup things.
If you write directly in javascript, there is now way to really optimize the code as much as one would with a real compiler.
The other interesting part is that one day, CoffeeScript or other generators to javascript could be used to analyse code (like jslint) and remove parts of the code where some variables aren't needed... Compile functions differently with different arguments to speed up things when some variables aren't needed. If you have purejs, you'll have to expect that there is a JIT compiler that will do the job right and its good for coffeescript too.
For example, I could optimize the coffee script one last time..by removing the new_way = (function... from inside the for loop. One smart programmer would know that the only thing that happen here is reaffection the function on each loop which doesn't change the variable. The function is created in the function scope and isn't recreated on each loop. That said it shouldn't change much...
time node test.js
real 0m5.363s
user 0m0.015s
sys 0m0.000s
So this is pretty much it.
Short answer: No.
CoffeeScript generates javascript, so its maximum possible speed equals to the speed of javascript. But while you can optimize js code at low-level (yeah, it sounds ironical) and gain some performance boost - with CoffeeScript you cannot do that.
But speed of code should not be your concern, when choosing CS over JS, as the difference is negligible for most tasks.
Coffescript compiles directly to JavaScript, meaning that there is always a one to one equivalent in JS for any Coffeescript source. There is nothing non-common about it. A performance gain can come from optimized things e.g. the fact that Coffescript stores the Array length in a separate variable in a for loop instead of requesting it in every iteration. But that should be a common practise in JavaScript, too, it is just not enforced by the language itself.
I want to add something to the answer of Loïc Faure-Lacroix...
It seems, that you only printed the times of one Browser. And btw "x.push(i)" is not faster that "x[i] = i" according to jsperf : https://jsperf.com/array-direct-assignment-vs-push/130
Chrome: push => 79,491 ops/s; direct assignment => 3,815,588 ops/s;
IE Edge: push => 358,036 ops/s; direct assignment => 7,047,523 ops/s;
Firefox: push => 67,123 ops/s; direct assignment => 206,444 ops/s;
Another point -> x.call(this) and x.apply(this)... I don't see any performance reason to that. Even jsperf confirms by that: http://jsperf.com/call-apply-segu/18
Chrome:
direct call => 47,579,486 ops/s; x.call => 45,239,029 ops/s; x.apply => 15,036,387 ops/s;
IE Edge:
direct call => 113,210,261 ops/s; x.call => 17,771,762 ops/s; x.apply => 6,550,769 ops/s;
Firefox:
direct call => 780,255,612 ops/s; x.call => 76,210,019 ops/s; x.apply => 2,559,295 ops/s;
First to mention - I used the actual Browsers.
Secondly - I extended the test by a for-loop, because with one call the test is to short...
Last but not least - now the tests for all browsers are like the following:
Here I used CoffeeScript 1.10.0 (compiled with the same code given in his answer)
console.time('coffee');// added manually
(function() {
var new_way;
new_way = function() {
var i, results;
return (function() {
results = [];
for (i = 0; i <= 1000000; i++){ results.push(i); }
return results;
}).apply(this);
};
// manually added on both
var i;
for(i = 0; i != 10; i++)
{
new_way();
}
}).call(this);
console.timeEnd('coffee');// added manually
Now the Javascript
console.time('js');
(function() {
function old_way()
{
var i = 0, results = [];
return (function()
{
for (i = 0; i <= 1000000; i++)
{
results[i] = i;
}
return results;
})();// replaced apply
}
var i;
for(i = 0; i != 10; i++)
{
old_way();
}
})();// replaced call
console.timeEnd('js');
The limit value of the for loop is low, because any higher it would be a pretty slow testing (10 * 1000000 calls)...
Results
Chrome: coffee: 305.000ms; js: 258.000ms;
IE Edge: coffee: 5.944,281ms; js: 3.517,72ms;
Firefox: coffee: 174.23ms; js: 159.55ms;
Here I must have to mention, that not always coffee was the slowest in this test. You can see that by testing those codes in firefox.
My final answer:
First to say - I am not really familiar with coffeescript, but I looked into it, because I am using the Atom Editor and wanted to try to build my first package there, but drived back to Javascript...
So if there is anything wrong you can correct me.
With coffeescript you can write less code, but if it comes to optimization, the code gets heavy. My own opinion -> I don't see any so called "productiveness" in this Coffeescripting language...
To get back to the performances :: The most used browser is the Chrome Browser (src: w3schools.com/browsers/browsers_stats.asp) with 60% and my testings also have shown that manually typed Javascript runs a bit faster than Coffeescript (except IE ... - much faster). I would recommend Coffeescript for smaller projects, but if no one minds, stay the language you like.
In my application (developed way back in 2006), the developers used dtree.js (Link) to render a hierarchy tree. The problem occurred when in 2010 the tree grew to 1300 nodes and depth of upto 13 levels. After this, the page started loading very slowly and in IE it gives the infamous "Stop running this script?" error. I want to improve the performance, but all my tricks have failed:
Caching variables, DOM elements.
Calculating array lengths outside loops.
Minimizing use of loops.
Apart from this, I tried to used setTimeout() to break the execution in smaller tasks, but I am not able to get it working as it has many restrictions. Also, I cannot move the rendering of tree to server side.
Any help is appreciated.
Thanks,
Sid
Typically what is slow in any browser is anything to do with the DOM.
If you can lazy-load any part of the tree's HTML representation, do it.
In general try to minimize the number of times your edit the DOM.
Example:
for(var i = 0; i < data.length; i += 1) {
dom_element.innerHTML += data.some_data;
}
vs
var string = "";
for(var i = 0; i < data.length; i += 1) {
string += data.some_data;
}
dom_element.innerHTML += string; // only one call to innerHTML, likely much faster!
innerHTML is also faster than using DOMDocument-style (document.createElement, element.append and so on)
We are using Bing and/or Google javascript map controls, sometimes with large numbers of dynamically alterable overlays.
I have read http://support.microsoft.com/kb/175500/en-us and know how to set the MaxScriptStatments registry key.
Problem is we do not want to programmatically set this or any other registry key on users' computers but would rather achieve the same effect some other way.
Is there another way?
Hardly anything you can do besides making your script "lighter". Try to profile it and figure out where the heaviest crunching takes place, then try to optimize those parts, break them down into smaller components, call the next component with a timeout after the previous one has finished and so on. Basically, give the control back to the browser every once in a while, don't crunch everything in one function call.
Generally a long running script is encountered in code that is looping.
If you're having to loop over a large collection of data and it can be done asynchronously--akin to another thread then move the processing to a webworker(http://www.w3schools.com/HTML/html5_webworkers.asp).
If you cannot or do not want to use a webworker then you can find your main loop that is causing the long running script and you can give it a max number of loops and then cause it to yield back to the client using setTimeout.
Bad: (thingToProcess may be too large, resulting in a long running script)
function Process(thingToProcess){
var i;
for(i=0; i < thingToProcess.length; i++){
//process here
}
}
Good: (only allows 100 iterations before yielding back)
function Process(thingToProcess, start){
var i;
if(!start) start = 0;
for(i=start; i < thingToProcess.length && i - start < 100; i++){
//process here
}
if(i < thingToProcess.length) //still more to process
setTimeout(function(){Process(thingToProcess, i);}, 0);
}
Both can be called in the same way:
Process(myCollectionToProcess);