Here is my javascript code, it is pretty simple:
console.profile();
var count = 1000;
var fn1 = function () {
for (var i = 0; i < count; i++) {
console.log("THIS IS FN1");
}
}
var fn2 = function () {
for (var i = 0; i < count; i++) {
console.log("THIS IS FN2");
}
fn1();
}
fn2();
console.profileEnd();
and this is my profile screenshot:
Why there are some gap in the image, just like my black rectangle marked?
What does this gap mean?
You see this non-uniform sequence of gaps between log calls on top of fn2 and fn1 because the profiler is sampling and gives you only statistical information. It will stop JS thread and capture current call stack roughly once per 1ms (100us in high res mode) and width of each bar is proportional to the number of consecutive samples where we've seen the same call stack.
The split of fn2 is a bug. Since we stop JS thread in random state it is not always possible to iterate JS call stack because e.g. top frame may be half-constructed. We do our best to determine current state of the VM and crawl call stack but sometimes our heuristics fail in which case we may end up capturing incomplete stack like in your case.
Related
Would anyone know a method (or trick) to force a rendering update to an MX ProgressBar in manual mode when using setProgress?
I have a situation with a block of code containing a couple of for loops which take a bit of time to complete. It would be tedious to unwrap this code to generate events, etc.
Update
Let me expand on this with a bit of pseudo code. I want to update the progress bar during operations on the contents of an array. THe for loops blocks so the screen isn't updating. I've tried validateNow() but that had no effect.
Is there some non-convoluted way I can either unwrap the for loop or use AS3's event model to update a progress bar? (I'm more accustomed to multi-threaded environments where this sort of task is trivial).
private function doSomeWork():void {
progressBar.visible = true;
for(var n = 0; n < myArray.length; n++){
progressBar.setProgress(n, myArray.length);
progressBar.label = "Hello World " + n;
progressBar.validateNow(); // this has no apparent effect
var ba:ByteArray = someDummyFunction(myArray[i]);
someOtherFunction(ba);
}
progressBar.visible = false;
}
In Flex, the screen is never updating while Actionscript code is running. It basically works like this:
Execute all runnable Actionscript code.
Update the screen.
Repeat continuously.
To learn more details, google for [flex elastic racetrack]. But the above is the nut of what you need to understand.
If you don't want a long-running piece of code to freeze the screen, you'll have to break it up into chunks and execute them across multiple frames, perhaps within a FRAME_ENTER event handler.
I am not sure what exactly is the problem. I tried the following code and it works without any need to validateNow.
protected function button2_clickHandler(event:MouseEvent):void
{
for(var n:int = 0; n < 100; n = n+20){
progressBar.setProgress(n, 100);
progressBar.label = "Hello World " + n;
// progressBar.validateNow();
}
}
<mx:VBox width="100%" height="100%">
<mx:ProgressBar id="progressBar"/>
<mx:Button label="Update Progress" click="button2_clickHandler(event)"/>
</mx:VBox>
I've created the standard player for dynamic sounds in a web app like so:
var _dynamicAudio:Vector.<Number> = new Vector.<Number>();
var _sampleIndex:uint = 0;
// ..Code to generate '_dynamicAudio' samples omitted
var _sound:Sound = new Sound();
_sound.addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleDataEvent);
_sound.play();
function onSampleDataEvent(event:SampleDataEvent):void {
var samplesRead:int = 0;
while (samplesRead <= 8192 && _sampleIndex < _dynamicAudio.length) {
var sample:Number = _dynamicAudio[_sampleIndex];
event.data.writeFloat(sample);
event.data.writeFloat(sample);
_sampleIndex++;
_samplesRead++;
}
}
However, on slower computers (or if I stress my own by opening other applications) the audio tends to 'garble' occasionally. It sounds like it gets stuck looping over a block of the most recent samples. When this happens, I've noticed that event.position jumps by some multiple of 8192, which would also seem to imply that onSampleDataEvent isn't being called for a few consecutive chunks of samples. If that's true, it would seem this issue is unavoidable. What I'd like to know is if there's any way to detect the garbling before it happens so I can pause the audio in place of the awful noise? Thanks!
It might be that the while() loop is heavy and you don't always have the memory/CPU power to process it. So it freezes and gives you the effect you described.
It might be possible to break up the loop into smaller loops, thus evening out the CPU load. At the same time processing the event far ahead enough to seamlessly playback the audio.
The following code is not tested and is only an example of how breaking up a loop could look like:
var _dynamicAudio:Vector.<Number> = new Vector.<Number>();
var _sampleIndex:uint = 0;
// ..Code to generate '_dynamicAudio' samples omitted
var _sound:Sound = new Sound();
_sound.addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleDataEvent);
_sound.play();
function onSampleDataEvent(event:SampleDataEvent):void {
var samplesRead:int = 0;
writeSamples(0, event);
}
function writeSamples(counter:int, eventReference:SampleDataEvent):void
{
var startTime:int = getTimer();
while (samplesRead <= (8192 - counter) && _sampleIndex < _dynamicAudio.length)
{
// check if the processing takes too long
if (getTimer() - startTime > 5)
{
writeSamples(counter, eventReference);
break;
}
counter++;
var sample:Number = _dynamicAudio[_sampleIndex];
event.data.writeFloat(sample);
event.data.writeFloat(sample);
_sampleIndex++;
_samplesRead++;
}
}
The main idea of the previewed code is to:
1) Check if the while loop is executed for too long. In my example 5ms is the limit
2) Break the loop if the execution is too long and start the loop again from the place it was stopped at.
If the whole process takes less than the limit, the loop will finish in one go.
You may want to refactor the code as it is not optimized and creates a lot of garbage instead of reusing objects.
Goal is to show progress of jpeg encoding from bitmap. I have couple of bitmaps that need to be encoded. So I get the total number of bytes as was suggested here:
for (var i:int = 0; i < bitmaps.length; i++)
{
bmp = bitmaps[i];
total_bytes += bmp.getPixels(bmp.rect).length;
}
Then I'm trying to show progress when doing asychronous encoding. I get a ProgressEvent which gives me bytesLoaded. So I calculate the progress like so:
total_loaded_bytes += event.bytesLoaded;
var percentage:int = ((total_loaded_bytes / total_bytes) * 100);
However, total_bytes does not add up to total_loaded_bytes. Total bytes loaded is way highter.
A wrong approach to use bytesLoaded property. This is not to be blandly added up, as this contains the total of already loaded bytes bu the Loader object that issued the event. And a wrong approach on getting total bytes too, you need to use event.bytesTotal from within the progress event listener, since you are loading bytes, not pixels. Even if you are uploading. Also, the exact progress may be totally unavailable for asynchronous encoding, you are only displaying the uploading/downloading progress.
Update: to receive an accumulated progress, do something like this:
var loaders:Array=[]; // array of loaders. Fill manually
var progress:Array=[]; // fill with zeroes alongside loaders, should be same size
function updateProgress(e:ProgressEvent):void {
var loader:Loader=e.target as Loader;
if (!loader) return; // or skip type coercion, we just need the reference
var i:int=loaders.indexOf(loader); // now get an index from array
if (i<0) return; // not found, drop it
progress[i]=e.bytesLoaded; // and update progress array with new value
// now sum up progress array and divide by aggregated bytesTotal
// this one is up to you
}
I've got 4 different types of markers on single map. Currently a slideshow rotates through each type, hiding the other 3. There is a MarkerClusterer object for each different type of marker so that they do not cluster together.
The issue I am having is that the heap snapshot in chrome shows I'm increasing the amount of memory in use by about 2mb every 5 minutes or so. This is my code currently:
function transitionMarkers() {
if (isSlideShowActive) {
for (var i = 0; i < markers.length; i++) {
if (nutrientsArray[slideShowCounter] === markers[i].address.SOURCE_GROUP) {
markers[i].setVisible(true);
} else {
markers[i].setVisible(false);
}
}
for (var n in types.NUTRIENTS) {
for (var sc in types.SOURCE_CODES) {
if (nutrientsArray[slideShowCounter] === n) {
markerClusters[n][sc].setMap(map);
} else {
markerClusters[n][sc].setMap(null);
}
}
}
}
incrementSlideShowCounter();
}
Markers have the ability to change their visibility, and since they will be re-rendered within a minute, I don't bother using setMap(null) on them. However, marker clusters do not have this option. When I examine the heap snapshot, I see thousands of objects that look like this:
[1076] :: pf #2451465 5 360 % 2 3360 %
b :: gi #2273271 2 120 % 170 5441 %
e :: function() #2454527 6 360 % 2 3000 %
proto :: pf #2338839 5 120 % 360 %
d :: "bounds_changed" #67519
It looks like there are thousands of these bounds_changed events sitting there accumulating...my map only hides or shows markers, it doesn't move around, zoom in or out, or anything like that.
Any thoughts?
These bounds_changed-events will be bound to the map when a ClusterIcon will be added(happens all the time when you call markerClusters[n][sc].setMap(map)).
When you call markerClusters[n][sc].setMap(null) the ClusterIcons will be removed, the onRemove-method also clears all listeners bound to the ClusterIcon-instances, but the onRemove-method does not remove the bounds_changed-events bound to the map(you may call it a bug).
So you may either fix the bug on your own and modify the markerclusterer.js so that it also removes the bounds_changed-event, or don't call setMap() at all, instead you may e.g. call the methods show() or hide() of the ClusterIcon-instances to show or hide them(should give a better performance).
EDIT I have had a rethink: I am going to use a much easier to implement tree structure with a grid so that each block can have up to 4 neighbours.
I am trying to attach blocks on to the stalk (series of blocks) of this flower. Green blocks are the existing stalk and the blue block is the one attached to the mouse.
The block attached to the mouse will correctly snap to the nearest edges (I'm allowing diagonals for now) however the blocks will also be able to go 'inside' the stalk (image 2) by snapping to a block above or below.
My question is, how can I stop this? I considered
Iterating the list again but ignoring the block I just tried to attach to; I think this will just result in the same problem really by attaching to another block 'inside' the stalk.
Find which block I am intersecting and get another connection point from it, repeat until there are no intersections; This seems the better option but could be very messy when intersecting more than 1 block at a time
I should note that I plan on having a smoother snap, not just arbitrarily to an edge, so a grid is pretty much out of the question. I am pretty confident there must be an elegant solution, I'm just not seeing it!
Here is my snapping code as it currently stands
var mousePos:Point = new Point(mouseX, mouseY);// new Point(e.stageX, e.stageY);
var nearestPoint:Point = null;
var nearestDistance:Number = 0;
for (var i:int = 0; i < mPlant.length; ++i) {
var part:PlantPart = mPlant[i];
if (part is Stalk) {
var connectionPoint:Point = (part as Stalk).getNearestConnectionPoint(mousePos);
var distance:Number = Point.distance(mousePos, connectionPoint);
if (nearestPoint == null || distance < nearestDistance) {
nearestPoint = connectionPoint;
nearestDistance = distance;
}
}
}
if (nearestPoint != null) {
mMousePointer.x = nearestPoint.x;
mMousePointer.y = nearestPoint.y;
}
You can always pre-calculate a bounding Rectangle for the stalk, and then do the snapping check against that Rectangle.
The Rectangle can be calculated using something like this (un-tested code, though)
var _bounding:Rectangle = new Rectangle(int.MAX_VALUE, int.MAX_VALUE,0,0);
for each( var part:PlantPart in mPlant)
{
if(part is Stalk)
{
_bounding.width = part.width; // Width will always be the same
_bounding.height = Math.max( _bounding.height, part.y );
_bounding.x = Math.min( _bounding.x, part.x );
_bounding.y = Math.min( _bounding.y, part.y );
}
}