EaselJS Perfromance Issue/Frame rate drops - javascript

I am working on the project below initially stages animation works fine but after 2nd level the Frame rate drops drastically, below is the link of the game can anyone look into and help me, please!
http://fbapps.ae/mfc/game-demo/
thanks
mustafa

Currently can not get passed level 1. The _animalClicked method shows that the _questions variable is undefined, so you get wrong answers indefinitely.
I would say if you can in fact get past this, and are seeing a frame drop, then it is likely your not properly cleaning up your stage or events.
A few other notes:
Get rid of all the stage.update() calls you have everywhere. Once you call handleComplete, you no longer need to update the stage, because there is a Ticker event which updates the stage constantly. You might want to consider just adding a ticker event initially, rather than waiting for the content to load.
Note that removeEventListener can not be called with no handler argument. Unlike jQuery, this does not mean "remove all events of this type". You are using anonymous handlers, so you will have to hang on to a reference to that function, and pass it to removeEventListener instead. Alternatively, you could use removeAllEventListeners(). Looks like you do that elsewhere.

Related

Javascript events using H.datalens.Provider

Are there any events to subscribe to using
H.datalens.Provider
? So one can know when all data has been loaded for example, or if there was an error.
I'm afraid not. There is an "update" event being triggered when the data gets updated (see https://developer.here.com/documentation/geovisualization/datalens/h-datalens-provider.html) but I do recall it triggering multiple times. Afaik there's no easy way to know the data has finished loading.
A trick I've seen using is listening to the event and starting a timeout, resetting it every time a new update event gets triggered. When the timeout is finally able to execute, the updates are over. This is not by any means a good solution, but might be of help.

How do I track down where event listener is getting added?

I have a fairly good sized javascript (with react/redux but no jquery) codebase for a webapp I'm building, and I've noticed that when I repeatedly open and close a certain panel within the UI, the number of listeners according to Chrome's performance timeline keeps increasing.
The graph looks like this:
I have allowed the chrome's performance monitor run for a good minute or two with the page sitting idle (just after opening/closing the panel a bunch), hoping that perhaps the listeners will get garbage collected, but they are not. I've switched to other tabs during this process, also hoping that the listeners will get garbage collected when the tab is backgrounded, but they unfortunately are not.
I therefore suspect that some listeners are getting registered that are never unregistered.
This leads me to two main questions:
Does my hypothesis that listeners are getting added and never
unbound seems sensible, or is there more I could be doing to confirm
this suspicion?
Assuming my suspicion is correct, how can I best go
about tracking down the code where the event listener(s) is/are
being added? I have already tried the following:
Looked at the code that is responsible for opening the panel in question, seeing where it adds any listeners, and commenting out those portions to see if there's any change in the performance graph. There is not a change.
Overridden the addEventListener prototype like so:
var f = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(type, fn, capture) {
this.f = f;
this.f(type, fn, capture);
console.trace("Added event listener on" + type);
}
Even after doing this, then commenting out all code portions that cause this console.trace to be executed (see #1) such that the console.trace is no longer printed upon open/close of the panel, I notice the same increase in listeners in the performance graph. Something else is causing the listeners to increase. I understand that there are other ways that listeners can be added, but it's not clear to me how to intercept all of those possibilities or cause them to be logged in Chrome's debugger in such a way that I can tell which code is responsible for adding them.
Edit:
- At the suggestion of cowbert in the comments, I took a look at this page:
https://developers.google.com/web/tools/chrome-devtools/console/events
I then made the following function:
function printListenerCount() {
var eles = document.getElementsByTagName("*");
var numListeners = 0;
for (idx in eles) { let listeners = getEventListeners(eles[idx]);
for(eIdx in listeners)
{
numListeners += listeners[eIdx].length;
}
console.log("ele", eles[idx], "listeners", getEventListeners(eles[idx]));
}
console.log("numListeners", numListeners)
}
I execute this function after having opened/closed the panel a bunch of times, but unfortunately the "numListeners" figure doesn't change.
If the numListeners figure changed, I would be able to diff the results before/after having open/closed the panel to discover which element
has the extra event listener registered to it, but unfortunately numListeners does not change.
There is also a monitorEvents() API described on https://developers.google.com/web/tools/chrome-devtools/console/events, but the function
call requires that you specify a DOM element that you wish to monitor. In this situation, I'm not sure which DOM element has the extra
listeners, so I'm not sure how the monitorEvents() call will really help me. I could attach it to all DOM elements, similar to how I've
written the printListenerCount function above, but I presume I'd run into a similar problem that I ran into with printListenerCount() --
for whatever reason, it's not accounting for the listener(s) in question.
Other notes:
This is a somewhat complicated reactjs (preact, technically) based application. Like most reactjs based apps, components get mounted/unmounted (inserted into and removed from the DOM) on the fly. I'm finding that this makes tracking down "stray event handler registrations" like this a bit tricky. So what I'm really hoping for is some general debugging advice about how to track down "Stray event handlers" in large/complex projects such as this. As a C programmer, I would open gdb and set a breakpoint on everything that can possibly cause the "listeners" number in the performance graph to increase. I'm not sure if there's an analog of that in the javascript world, and even if it there, I'm just not sure how to do it. Any advice would be much appreciated!
Thanks for your comments, everyone. I ended up figuring this out.
From my OP:
Does my hypothesis that listeners are getting added and never unbound seems sensible, or is there more I could be doing to confirm this suspicion?
It turns out that the answer to this question is: The hypothesis is not sensible. The listeners simply haven't had a chance to get garbage collected yet. It can take some more time than you might think.
Here's how I figured it out:
I failed to realize that while recording a performance timeline, it's possible to force a garbage collection by clicking on the trash can icon in the Performance tab (same tab used to start the timeline recording). By clicking this icon after repeated closings/openings of the UI panel, the extra listeners completely went away. The graph now looks like this, with the dips being moments where I clicked the trash icon:
Apparently, backgrounding the tab and waiting a couple of minutes like I mentioned in the OP is simply not enough time for garbage collection to occur on its own; It takes some more time than that.
I wasn't aware of the ability to manually collect garbage with the trash can icon when I wrote the OP... I strongly recommend using it before going on any wild goose chases hunting down what might at first look like a performance problem.

js newbie trying to understand the dom via ajax confusion (conceptual)

I'm a python/data guy mucking around in a little bit of web, fundamentally clueless about JS and the dom and all that. So something really weird happened, and even though I found a solution, I'm trying to understand the mechanics of why.
The scene: a common problem
There's like a million prior SO questions that go along the lines of "I had some working jQuery/JS that manipulated some HTML. Then instead of hard-coding the relevant HTML, I created it programatically somewhere else and dragged it in via AJAX. Suddenly everything broke."
Invariably, the answer goes like this: "you can't do that. Hook up your code to something higher up the parent-child chain, event delegation is a magic thing and it will save you."
So that happened to me, I spent an hour or so reading prior SOs and learning about event delegation, and, indeed, it saved me, and my code worked.
But I don't understand why it was broken in the first place. So I'm hoping someone can explain the underlying theory to me, and that way I'll come to a deeper understanding of the whole dom bit.
Some Broken Code
$(document).ready(function(){
$("#autopubs").load("pubslist.html");
// Obviously, the stuff in pubslist.html is what the next line was
// supposed to work on
$('.collapse').on('show.bs.collapse', function () {
$('.collapse.in').collapse('hide');
});
});
probably no surprises about the solution. wrap autopubs in an outer div and hook the collapse thing to that. Done, worked, deeply dissatisfied.
But I still don't understand why this is necessary. Here's my mental model of what the broken code should have been doing.
Ok, the document's finished loading! Let's execute our code!
First line: let's go get this file and add it to the DOM. This is out there in the world as state, and now we're going to mutate it, as one does with state.
Ok, now it's part of the DOM. We're done with that line. Let's go to the next line.
Ok, now we want to hook up a bunch of event listeners to everything with the class collapse. Cool, let's look up the present state of the DOM. Hey look, there's all this stuff in there with the collapse class. Bam. Hooked up.
Except 4 never happened, because the second line of code apparently couldn't see all the stuff that the first line added.
Intuitively, there are two plausible reasons for this:
The second line executed before the first one finished getting the file in. If that's true, then I've learned something important about javascript (or jquery, or ajax, or something): lines don't always execute in order, or at least don't always finish before the next one starts.
The first line didn't actually mutate any state at all. The DOM isn't state. It's something else, something... maybe even immutable? The first line tinkered around with something else entirely, something the second line couldn't touch because it was trying to tinker with the DOM.
Honestly, both of those possibilities seem kind of bizarre to me. But there's obviously something I fundamentally don't understand going on under the hood here. Can someone help me?
JavaScript makes heavy use of asynchronous behaviour. Lines execute in order within the same function, but that doesn't mean they "complete" their action.
If you look at the documentation for load (http://api.jquery.com/load/) you can see that it takes an optional complete parameter. That is a callback. It is a function that will be ran when the operation completes. Calling load itself only makes the loading start, sort of "in the background".
So you could do this:
$(document).ready(function(){
$("#autopubs").load("pubslist.html", function() {
$('.collapse').on('show.bs.collapse', function () {
$('.collapse.in').collapse('hide');
});
});
});
The callback to load is ran after it completes.
Why your original hack-solution actually works? It attaches the event handler to an existing outer div, and the loaded HTML is put inside later, when it loads.
Your first assumption is correct. When calling ajax its asynchronous which means it will run a callback when complete. In this case jquery already calls a callback to append the content to the div but that happens after a delay of maybe 100 to 200ms or so.
The other code however can be run instantly but doesn't find anything because the async call isnt finished yet.
In jQuery if you check the documentation for load you will see something along the lines of (arg1, [arg2], [complete]) where complete will be a closure or callback function.
If you wrap the code within that callback function instead of below it than that code will be executed after the content is loaded and added.
EDIT
The load load is also one of the convenience / shorthand method in jquery. For more documentation check Ajax
Furthermore the DOM is very mutable and your first line that does the request does perform an operation on the dom. Due to the fact that it is async it will tell the script to continue running while it waits for its data which is why it fails.
Hope this helps abit! You've got the right picture :)
If I correctly understand, you should refer the new loaded DOM only on a 'complete' callback. Take a look here:
http://api.jquery.com/load/
$( "#result" ).load( "ajax/test.html", function() {
alert( "Load was performed." );
});
The first line did get executed, it changed the state. After that, you hooked an event to the change and that will get called everytime there is a change, but not for the first one since it has already happened before the event was hooked up.
jQuery.load is asynchronous, meaning you need to provide any code to execute after the content is added via callback. You have a working example at the bottom of the documentation page.
As others stated JavaScript wont wait with finishing the load function before executing the following lines. Therefore, you can use the callback parameter of the load function (or any other function that takes time, like AJAX or animations). So your first assumption is correct. AJAX (asynchronous JS) is a huge thing, you should dig into it :)
Additionally, you still can use delegation in your case:
$(document).on('show.bs.collapse', '.collapse', function () {
var collapse = $(this); // the individual $('.collapse') element triggering the event
});
This will bind the show.bs.collapse event to all .collapse elements, regardless if they exist now or are added later. Here the original selector is the $(document). In simple words:
"Hey document, whenever the event show.bs.collapse gets fired on an element with the selector '.collapse', run the following code."
You distinguish between direct and indirect event delegation or binding. In your example, you use direct binding, since you are ultimately selecting all now-existing .collapse elements and then do stuff with them:
$('.collapse').on()
You have to understand that this works only for currently existing elements that get selected when running that line. This wont apply for dynamically added elements of the same class.

Check if scroll is triggered or not

I am building a website and in this website I have an event on my mousewheel. The problem is that when you scroll your mouse on a mac (with a magic mouse) the scroll event is called so many times that at one moment the scroll function will totally freak out and isn't smooth anymore.
Does anyone know how you can tackle this problem?
I already tried to check the e.orginalEvent but it always returns DOMMouseWheel.
Also on a PC you don't have this problem and with an other mouse then the magic mouse it works great.
Thanks
Sounds like you need the debounce/throttle plugin here http://benalman.com/projects/jquery-throttle-debounce-plugin/ .
It allows you set up events to fire only after a certain period like 1 second. This way your page Isn't flooded with mousewheel events or if someone thinks clicking the submit button of a form a MILLION times will make it submit faster...
Try using something like underscore.js's throttle function.
From the documentation:
Returns a throttled version of the function, that, when invoked repeatedly, will only actually call the wrapped function at most once per every wait milliseconds. Useful for rate-limiting events that occur faster than you can keep up with.

How can I make a jQuery "ready" event handler fire after all the other ones?

I am working on a Greasemonkey script that will actually upgrade the version of jQuery used on the page. To do this, I need to add a "ready" event handler that will fire after all the other ones that might be on the page.
I know that jQuery waits for the DOM to be manipulable before invoking the ready event handlers, so is there a way to influence the order in which it executes them? Thank you,
They are called in the order they are registered. So from the top of the page to the bottom. If you need this to be the last registered ready callback register it at the very end of the body tag. Also use the $(window).load as opposed to $(document).ready.
The ready handlers are added to a readyList Array, which I'm pretty sure is private, so I don't think you'll be able to influence it directly.
One thing you could perhaps do is add your code to the readyList, but place it in a setTimeout() so it waits a bit to execute. Hopefully all the others will be done first.
Still, you may have troubles when upgrading jQuery like this. For example, there may be differences in the implementation of jQuery.cache which stores event handlers, and other data.
So if jQuery.cache was populated with one version, it may not be compatible with another.
How to control the order of functions being called in jQuery $(document).ready
According to answers given to the question above, they should fire in the order they are added (the ajax-calls in that specific question add more mud to the water than in your question).

Categories