this fadeIn / fadeOut jQuery code crashes my browsers- Why? - javascript

I created this code for a conference website that I had been tasked to do. It is a simple fade in and out loop using window.setInterval. I've tested it on firefox, safari and google Chrome. The first 2 just stop responding after awhile, while google chrome gives me a note saying that the script uses too much memory. Which part of my script is using too much memory and how should I rectify it ?
As the conference site is currently used for marketing, I have to revert to my backup copy. Therefore, I am unable to give a URL for this problem. I will, however, provide one as soon as I get my dummy site up
<span id="alertTxt" style="text-align:center; color:#CC0000; display:none">Director of Information Technology, Network Communications, Security, Smart Metering, Operations, C-Level Executives</span>
<span id="alertTxt2" style="text-align:center; color:#CC000; display:none">This Conference is for You!</span>
<script type="text/javascript">
function animateTxt() {
$j("#alertTxt").fadeIn(2000);
$j("#alertTxt").delay(6000).fadeOut(1500);
animateTxt2();
window.setInterval("animateTxt()",22000);
}
function animateTxt2() {
$j("#alertTxt2").delay(1500).fadeIn(2000);
$j("#alertTxt2").delay(6000).fadeOut(1500);
}
animateTxt();
</script>

setInterval is used to set a repeating timer. if you keep using setInterval at the end of animateTxt() then you'll end up with lots of timers. either change it to setTimeout or move it out of the function.

You should re-write this to trigger when complete, like this:
function animateTxt() {
$j("#alertTxt").fadeIn(2000).delay(6000).fadeOut(1500, function() {
$j("#alertTxt2").delay(1500).fadeIn(2000).delay(6000).fadeOut(1500,function(){
animateTxt();
});
});
}
animateTxt();
Instead of queuing animations that may or may not finish on time, ending up in a growing queue, this triggers the animation to loop when complete. The method you currently have grows at linear rate, and animations begin stacking up and the queue builds fast...this ensures only one cycle is going at a time.

Related

How to properly wait for browser reflow/repaint to finish

Let's say I have a complex HTML component that I want to animate, but every time it needs to be animated, several things need to be done, such as rendering new HTML components, setting height, attaching css classes, etc....
This could cause the animation not being smooth if the animation gets triggered in the middle of browser reflow/repaint. I could potentially use setTmeout to delay the animation, but how long it should wait is not clear.
Is there any bullet-proof way to wait for all these browser rendering work to be done?
Use window.requestAnimationFrame() (https://developer.mozilla.org/en/docs/Web/API/window.requestAnimationFrame) - you use it in essentially the same way you would use setTimeout, but you don't specify the delay - the browser deals with it for you.
Article about it from Paul Irish here: http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
Eg:
stepAnimation = function () {
// Do something to move to the next frame of the animation
// then
step()
}
step = function () {
window.requestAnimationFrame(stepAnimation)
}
step()

Example on how to use seek(time, [callback]) in Flowplayer

I'm trying to understand the flowplayer API, I'll be honest, I really need examples to get this stuff. I know some of you ninjas know what you're doing quite easily.
I am building a video training page for someone. It uses a PHP (kirbycms) framework to generate pages. I understand how to drop my variables and all that stuff. I have the videos working. It would be largely beneficial if I could have cue points that trigger things, and buttons that seek to specific time codes. It would be best if I can use PHP to define a string for these links.
I am looking for an example on how to use seek(time, [callback])
I am also looking for an example of
$(".player").bind("cuepoint", function(e, api, cuepoint) {
// here we use custom properties left, top and html
$("#info").html(cuepoint.html).animate({
left: cuepoint.left,
top: cuepoint.top
});
});
Update
Included bootply, this still does not work for me. Is it because my controls are outside of the flowplayer window?
http://bootply.com/86532
seek function (as documentation says: CLICK) is for jumping into given time on the timeline:
seek(time, [callback])
It takes two arguments: time in seconds and a callback - function that will be executed after jumping into that time on the timeline. Assuming that you are using jQuery you can write something like this to jump into 15.5s of the movie if you click button and then alert some message (just a simple example):
flowplayer(function (api, root) {
$("#someButton").on('click' function(e){
e.preventDefault();
api.seek(15.5, function(){
alert("you've jumped to 15.5s of the movie!");
});
});
});
Flowplayer doesn't do what you're after. In fact, seek() pretty much does the opposite- it triggers the video to jump to that point in time (and optionally calls back when its done).
If you want to set cuepoints and have the video trigger code when the video reaches those points in time, have a look at addEventListener("timeupdate", callback), see docs.
You might also want to check out popcornjs.

Add automation to a jQuery Content Slider

I'm looking for some help to implent a timer for this script I'm linking to.
As it is now, it toggles different slides when hovering the list to the right, but I want the slider to automatically jump ahead to the next slide after a certain amount of time until it reaches the end and then goes back to the top.
The catch though is that it also needs to work as it is now, so that you can toggle via hovering and when you stop hovering it should remember the position and jump ahead to the next item.
I realize this is alot to ask for, but some pointer would be great, thanks alot!
DEMO: http://jsbin.com/acorah
Your code is taking a bit of a performance hit with that each() loop which I don't think you need. You're binding events inside the loop and you're limiting your possibilities by declaring your actions inside the bind() scope. You want to be able to call events on any object and not only a single element; $('.cn_item') in your case.
The idea is to keep track of your current slide with a class, let's say .cur.
Then you create an object where you declare all your methods. The main methods or actions are getCur() and goTo() and mostly everything else will use these. ie. next() is just a shortcut for goTo()
var actions = {
getCur: function(){ return idx; },
goTo: function(idx){
// The simplest case
$slides.hide().eq(idx).show();
},
next: function(){ this.goTo(this.getCur()+1); },
prev: function(){ this.goTo(this.getCur()-1); }
.
.
.
}
Now you can call actions on events by simply doing this:
$slides.click(function(){ actions.goTo($(this).index()); });
$next.click(function(){ actions.next(); });
And then you can setInterval() to add a timer.
setInterval(actions.next, 1000);
This tutorial might help. I basically cover everything involved in making a slider. I would change some things as of today, we learn new ways to code stuff everyday.

Does browser rendering and JavaScript execution happen simultaneously?

For example, if I have this:
$('#button').click(function() {
$.get('/question', function(data) {
$('#question').html(data);
$('#question').dialog( ... );
});
return false;
});
Will the user see the question content for a brief moment before the dialog is shown?
Note: Normally I'd just hide the #question manually, but there's actually a step in between html() and dialog() with another jQuery plugin where the content must not be 'hidden'.
Short Answer
Yes, it's possible that the user will see the question content for a brief moment before the dialog is shown.
The Fix
To guarantee you won't momentarily see the contents of #question before displaying the dialog, absolutely position #question offscreen before displaying it. After that, call the jQuery plugin that requires #question to be displayed. Finally, hide #question and restore its position.
CSS
#question
{
display: none;
}
JavaScript
$('#button').click(function() {
$.get('/question', function(data) {
var question = $('#question');
question.html(data);
var position = question.css('position');
var top = question.css('top');
var left = question.css('left');
question.css({ position: 'absolute', top: -1000, left: -1000 }).show();
//whatever you need to do with #question while it's not hidden
question.hide().css({ position: position, top: top, left: left });
question.dialog( ... );
});
return false;
});
The browser will render the DOM up until that call, at which point it will stop and parse/execute your js. This is why it's considered best practice to put all script tags at the bottom of a page (so that the browser can render enough of the DOM so your visitors aren't stuck staring at a blank white screen).
Using
$(document).ready();
can alleviate this to an extent, but if you're truly concerned with when it is added to the DOM, make sure your code is added at the very bottom of your HTML's body tag.
References:
http://developer.yahoo.com/blogs/ydn/posts/2007/07/high_performanc_5/
In your case absolute not, because you are using a framework. It works like this:
1) Script code is requested from external files as the page progressively loads. An HTML parser has to parse the script tags before there is any awareness of a script request. This code executes when called, but it is fed into the JavaScript interpreter the moment it is available to the JavaScript interpreter.
2) Script code resident directly in the page is fed into the interpreter as the HTML code is parsed by an HTML parser and a script tag is encountered. Code inside functions executes when called, with one exception. Otherwise code executes immediately upon interpretation. The one exception is when a function block is immediately followed by "()" which indicates immediate invocation.
3) Most code that executes initially executes from function calls made with the "onload" event. The onload event occurs when the static DOM is fully available from the HTML parser and when all asset requests from the initial static HTML are requested. In some edge cases with older browsers it is possible for conflicting conditions to occur that create a race condition in the page that prevents the onload event from ever firing or after an extraordinary delay.
4) You are using jQuery, so you are at a severe disadvantage with regards to speed of availability. jQuery code is JavaScript code, so it has to enter the JavaScript interpreter exactly like any other JavaScript. All the prior points from this post must be observed before any jQuery code can execute.
5) When I perform A/B testing I need code to execute as absolutely as early as possible and as fast as possible to minimize flicker on the page, so frameworks are definitely not an option. In this case I follow these steps:
5a) I find the first id attribute directly after the DOM node(s) that I need to access.
5b) I write a function to test for the availability of this node. If the node is available then the areas above it are available, so I am know I am solid. Consider the following example:
var test = function () {
var a = document.getElementById("first_node_lower_than_I_need");
if (a !== null && typeof a === "object") {
//my code here, because I know my target area is available
} else {
setTimeout(test, 100);
}
};
setTimeout(test, 100);
5c) Notice in the sample code above that I call my function with a setTimout delay to give the DOM a fighting chance. If the function executes early that is okay because I am calling it recursively with a delay to give the DOM some extra time to load. If you set your delay to 50ms or lower you are increasing execution time in IE8 and lower because of numerous unnecessary calls for the function. I recommend keeping the delay at 100ms for an ideal balance cross browser, but if you really want rapid execution in new browsers then set the first delay to 50ms, this is the one outside the function, and keep the other at 100ms.
5d) Minimize your use of innerHTML property with the above method, or be very familiar with the targeted page to know when it is okay to use innerHTML. The problem with innerHTML is that it changes the page output without reporting those changes back to the parsed DOM in memory, which normally is an irrelevant disconnect. However, in this case it is certainly relevant because of how fast and early your injected code can execute. This is a problem because other code that executes later, such as with the onload event or jQuery's ready event, will either overwrite your changes or will not be able to find their respected DOM load and simply drop their execution all together. This is particularly an important concern if you are targeted a very high level node in the DOM tree, so for your safety be very specific when selecting nodes to use innerHTML or just use DOM methods. This is a bit more complicated in that you cannot use a DOM method only solution because you cannot change text nodes with the nodeValue method cross-browser as this is not supported in IE7.
If you need to execute JavaScript code before completion of DOM parsing then do not use a JavaScript framework. Write using plain regular JavaScript code and optimize the hell out of it. Otherwise you will always have flicker and the larger of the static HTML download the longer and more noticeable that flicker will be. Additionally, jQuery code tends be far slower to execute than regular optimized JavaScript due to its reliance on CSS like selectors. If your injected jQuery code is required to perform a large task on a very large static HTML document then it is unlikely to complete execution in IE7 without timing out.
This is the reason initializing any DOM-related activity should be done/triggered from within $(document).ready() .
So if you put you $.get statement inside of doc ready, you can ensure that all the elements in the HTML have been rendered and are ready to be interacted with via JS.
$(document).ready(function () {
$.get('/question', function(data) {
$('#question').html(data);
$('#question').dialog( ... );
});
});

Jquery setInterval too fast when coming from another tab

I've got a site with endlessly sliding images using jquery's setIntervall() function.
When calling the page in Chrome 13 and I switch to another tab to come back a few seconds later the image sliding is happening faster, as if it tried to keep up to where it was if it hadn't switched to another tab.
How could I resolve this issue?
$(window).load(function() {
setInterval(nextSlide, 3500);
});
function nextSlide(){
offset += delta;
$("#slideContent").animate({left: -1 * offset}, 1000);
}
At the beginning I would like to apologize for all the mistakes - my English is not perfect.
The solution of your problem may be very simple:
$(window).load(function() {
setInterval(nextSlide, 3500);
});
function nextSlide(){
offset += delta;
$("#slideContent").stop(true,true).animate({left: -1 * offset}, 1000);
}
inactive browser tabs buffer some of the setInterval or setTimeout functions.
stop(true,true) - will stop all buffered events and execute immadietly only last animation.
This problem will also appears in Firefox > 5.0 - read this article: Firefox 5 - changes
The window.setTimeout() method now clamps to send no more than one
timeout per second in inactive tabs. In addition, it now clamps nested
timeouts to the smallest value allowed by the HTML5 specification: 4
ms (instead of the 10 ms it used to clamp to).
here you can read, how animate works - it fires setInterval function many times. How animate really works in jQuery
The latest versions of Chrome apparently slow down the operation of setInterval when a tabbed page is in the background and then when you bring that page forward it tries to catch up.
On the Chromium blog, Google said:
In the forthcoming Chrome 11 release, we plan to reduce CPU consumption even for pages that are using setTimeout and setInterval. For background tabs, we intend to run each independent timer no more than once per second. This change has already been implemented in the Chrome dev channel and canary builds.
Your interval is 3.5 seconds, but the animation itself may be using much shorter timers.
Possible ways to work-around it:
Stop your timer/animation when the window is not visible. Restart the timer/animation when the window becomes visible.
Instead of setInterval, use setTimeout and then just reset the setTimeout each time it fires to create your own repeating interval - though in your case, it may be jQuery's use of timers that are the issue - I don't know.
Slow your timers down so they don't run afoul of this (again might be inside of jQuery not your own timers).
The best option is probably to figure out when to just stop and then restart the animation.
Similar question here: Chrome: timeouts/interval suspended in background tabs?.
FYI, Chrome has new experimental API for detecting page visibility for just this reason. You can read about it here: http://code.google.com/chrome/whitepapers/pagevisibility.html. it helps solve the issue when your page is visible, but doesn't have focus.
Hey are you using Jquery 1.6?
This may be the cause since 1.6 uses requestAnimationFrame for animations.
You may want to check this page out for a replacement for setInterval, clearInterval
http://blog.blenderbox.com/2011/06/24/jquery-1-6-1-and-setinterval/
code:
https://gist.github.com/1002116 [edit: updated source, edit2: currently doesnt work with firefox due to firefox bug. -- I had do downgrade to JQuery 1.5]
From the blogger:
Then, where you were calling setInterval(func, poll), you now call
requestInterval(func, poll). Where you call clearInterval(interval),
you now call clearRequestInterval(interval);
Have you tried not using setInterval or setTimeout at all, but just use the complete function of the animate function to kick off the next slide? The delay function is set to 2500 ( i.e. 1000 for the animate subtracted from the 3500 of the setInterval). I haven;t tried this with Chrome, so please let me know if it works.
var slider = function(n){
$("#slideContent").delay(2500).animate({left: -1 * n * delta},
1000,
function(){slider(n+1)}
);
};
slider(1);
try setInterval() it works
<script type="text/javascript" src="js/jquery-1.5.js"></script>
<script type="text/javascript">
var i=1;
$(document).ready(function(){
slideShow();
$("#next").click(function(){
slideShow();
});
});
function slideShow(){
if(i<3){
$("#slide-container").animate({ left:"+=35px" }, { duration:500})
$("#slide-container").animate({ left:"-=735px" }, { duration:250})
i++;
}
else {
$("#slide-container").animate({ left:"+=1400px" }, { duration:1000})
i=1;
}
setTimeout('slideShow()',2000);
}
</script>

Categories

Resources