Nonconcurrent async recursion - javascript

My end goal is to mitigate as much lag (window freezing/stuttering) as possible, giving the client a responsive window from page load.
My program is a Chrome extension, and part of it needs to search through a reddit submission, including all comments for certain words and then do some stuff with them. After this answer, I converted my code to use setInterval for the recursive search. Unforutnately, this runs concurrently, so even though each branch in the comment tree is delayed from its parent, the overall search overlaps each other, negating any benefit in the delay.
I have a solution, but I don't know how to implement it.
The solution would be to have a callback when a branch runs out that goes to the nearest parent fork. This in effect would traverse the comment tree linearly and would allow the setInterval (or probably setTimeout would be more appropriate) to have a noticeable affect.
The code that would need to be changed is:
function highlightComments(){
var elems = $(".content .usertext-body > .md");
var index = 0;
var total = elems.length;
console.log("comments started");
var intId = setInterval(function(){
highlightField(elems.get(index));
index++;
if(index == total){
clearInterval(intId);
addOnClick();
console.log("comments finished");
}
}, 25);
}
and highlightField is:
function highlightField(node) {
var found = $(node).attr("data-ggdc-found") === "1";
var contents = $.makeArray($(node).contents());
var index = 0;
var total = contents.length;
if (total == 0){
return;
}
var intId = setInterval(function() {
if (contents[index].nodeType === 3) { // Text
if (!found){
//Mods
var content = contents[index].nodeValue.replace(new RegExp(data.mods.regex, "gi"), data.mods.replacement);
//Creators
content = content.replace(new RegExp(data.creators.regex, "gi"), data.creators.replacement);
//Blacklist
for (var key in data.blacklist.regex){
if(data.blacklist.regex.hasOwnProperty(key)){
content = content.replace(new RegExp(data.blacklist.regex[key], "gi"), data.blacklist.replacement[key]);
}
}
if (content !== contents[index].nodeValue) {
$(contents[index]).replaceWith(content);
}
}
} else if (contents[index].nodeType === 1) { // Element
highlightField(contents[index]);
}
index++;
if(index == total){
clearInterval(intId);
}
}, 25);
}

Related

print javascript while loading

This is my code:
function myFunction(text, word){
var pos1;
do{
pos1 = text.indexOf(word);
if(pos1 !== -1){
document.getElementById("id1").innerText = pos1;
}
}while(pos1 == -1);
}
myFunction(text, "sun");
myFynction(text, "rain");
myFynction(text, "gold");
myFynction(text, "hello");
myFynction(text, "laptop");
myFynction(text, "tree");
I get text from file_get_contents of a page.
This page is continuously updating so, slowly, i will find those words through myFunction. What I want is to print those function meanwhile they finish
I really don't know if it's possible to use javascript to continuously monitor the HTML that is being loaded into the current page. It would require a few tests. However this would be my approach. (This function stops after finding one of the words in the array and displaying the pos)
var words = ['sun', 'rain', 'gold', 'HTML'];
function myFunc() {
var text = document.body.innerHTML;
var pos1;
for (var i=0; i < words.length; i++) {
pos1 = text.indexOf(words[i]);
if(pos1 !== -1){
document.getElementById("id1").innerText = pos1;
break;
}
}
if (pos1 === -1) {
// wait 1 second, try again
setTimeout(myFunc, 1000);
}
}
myFunc();
<div id='id1'></div>

Scroll to pure javascript not working

Yes I am avoiding a 3rd party lib on purpose, very small app on mobile device and don't want to pull anything.
I am trying to scroll to elements on a page using this scrollTo function:
function scrollTo(element, to, duration) {
if (duration <= 0) return;
var difference = to - element.scrollTop;
var perTick = difference / duration * 10;
setTimeout(function() {
element.scrollTop = element.scrollTop + perTick;
if (element.scrollTop === to) return;
scrollTo(element, to, duration - 10);
}, 10);
}
I grab a list of span tags that I want to use as my scroll points each time the user clicks a next button:
var index = null;
function next() {
var list = document.querySelectorAll("span");
var element = null;
if (index == null) {
index = -1;
element = document.body;
} else {
element = list[index];
}
index++;
if (index >= list.length) {
return;
}
var to = list[index];
scrollTo(element, to.offsetTop, 250);
}
The first next click properly scrolls to the first element. However the next click does not scroll. I debugged into the scrollTo method and it seems the element.scrollTop variable is not changing each time it is assigned. Any ideas?
You musst change the element.scrollTop of the element you want to scroll on, in this case document.body. You are only doing this in the first call. After that you´re always scrolling on the list item which is your target (what has no effect, since it has no overflow).
You should call your scrollTop like this:
scrollTo(document.body, to.offsetTop, 250);
Maybe you should also take a look at
window.scrollTo()
https://developer.mozilla.org/en/docs/Web/API/Window/scrollTo
I was not able to replicate your exact issue, but what I did find was that I was not able to get to the last span with the way your code was written. To get around that, I rewrote a few things. It may fix the issue for you.
function next() {
var list = document.querySelectorAll("span");
var element = null;
if (index == null) {
index = -1;
element = document.body;
} else {
element = list[index];
}
if (index >= list.length) {
return;
}
if(index >= 0)
{
var to = list[index];
scrollTo(element, to.offsetTop, 250);
}
index++;
}
Essentially, you were trying to increment your index too soon causing it to never process the last span.

Custom Lazy Load - IE9 Memory Leak

I'm currently developing a basic image gallery that dynamically loads new images in the following order (on document.ready):
Uses an ajax call to get JSON which contains all the information needed to dynamically render images.
Iterates over the JSON object to create proper divs/img elements which are then appended to the page.
$.ajax({
url: '/wp-content/themes/base/library/ajax/posts-json.php',
type: 'get',
//dataType: 'json',
success: function(data) {
// turn string response to JSON array
window.responseArray = JSON.parse(data);
window.lastPhotoIndex = 0;
// make sure there is a response
if (responseArray.length > 0) {
// get container
var container = document.getElementById("photos-container");
var ulElement = document.createElement('ul');
ulElement.className = "rig columns-3";
ulElement.setAttribute("id", "photo-list");
// iterate over each response
window.photoCount = 0;
for (var i = 0; i < responseArray.length; i += 1) {
// Only load first 10 images
if (responseArray[i]["post-type"] == "photo" && photoCount < 20) {
// Set the last photo index to this photo
lastPhotoIndex = i;
// create the li
var liElement = document.createElement("li");
liElement.className = liElement.className + responseArray[i]["day"];
//create class name string from WP tags
if (responseArray[i].tags.length > 0) {
for (var ii = 0; ii < responseArray[i].tags.length; ii += 1) {
nospaceTagName = responseArray[i].tags[ii].split(' ').join('');
liElement.className += " " + nospaceTagName;
}
}
//create image element and append to div
var imgTag = document.createElement("img");
imgTag.src = responseArray[i]["thumb-url"];
liElement.appendChild(imgTag);
//Add modal class info to outer div
liElement.className += " md-trigger";
//Add data-modal attribute to outer div
liElement.setAttribute("data-modal", "photo-modal");
ulElement.appendChild(liElement);
//next slide
photoCount++;
}
}
//append ul to container
container.appendChild(ulElement);
}
},
error: function(xhr, desc, err) {
console.log(xhr);
console.log("Details: " + desc + "\nError:" + err);
}
});// end ajax call
After the ajax call, I add a window scroll event that will be called while there are still more photos in the JSON object.
// Window scroll event
$(window).scroll(function () {
var trigger = $(document).height() - 300;
if (trigger <= $(window).scrollTop() + $(window).height()) {
//Call function to load next 10
loadNextPhotos();
}
});
The function called by the scroll even simply starts off at the previously left off index (lastPhotoIndex variable set at the beginning of ajax call - 'window.lastPhotoIndex'). The function looks like this:
function loadNextPhotos() {
if (photoCount < getPhotoCount()) {
var photosOutput = 0;
var startingIndex = lastPhotoIndex + 1;
var photoList = $('#photo-list');
for (var i = startingIndex; i < responseArray.length; i += 1) {
if (responseArray[i]["post-type"] == "photo" && photosOutput < 10) {
lastPhotoIndex = i;
photosOutput++;
// create the li needed
var element = document.createElement("li");
element.className = responseArray[i]["day"];
//create class name string from tags
if (responseArray[i].tags.length > 0) {
for (var ii = 0; ii < responseArray[i].tags.length; ii += 1) {
nospaceTagName = responseArray[i].tags[ii].split(' ').join('');
element.className = element.className + " " + nospaceTagName;
}
}
//create image element and append to li
var imgTag = document.createElement("img");
imgTag.src = responseArray[i]["thumb-url"];
element.appendChild(imgTag);
//Add modal class info to li
element.className = element.className + " md-trigger";
//Add data-modal attribute to outer div
element.setAttribute("data-modal", "photo-modal");
photoList.append(element);
// Keep track of photo numbers so modal works for appropriate slide number
photoCount++;
}
}
}
}
Bear in mind, this code is stripped down a lot from the full application. It works fine in Chrome, Safari, Firefox, IE10+.
When loaded in IE9, I'm experiencing crazy memory leaks as I hit the scroll event and append more items to the UL.
My guess is that I'm not following best practices when creating new items to be appended and they're staying in memory longer than they should. The only issue is I'm not sure how to solve it/debug it because the page crashes so quickly in IE9.
Any help would be awesome. Thanks!
EDIT:
I've tried implementing Darmesh's solution with no real luck. As I said in his comment it only delays the rate at which memory is leaked. I've also added jquery.visible.js on top of a scroll event so it looks like this:
$(window).scroll(function () {
if($('#lazy-load-trigger').visible() && window.isLoadingPhotos != true) {
console.log("VISIBLE!");
loadNextPhotos();
}
});
But it also only delays the memory leak. I still believe there are issues with Garbage Collection in IE9, but am not sure how to troubleshoot.
I think this is due to the browser calling loadNextPhotos function multiple times at the same time every time you scroll. This might work, give it a try,
function loadNextPhotos() {
// Add flag to indicate new photos adding started
window.isLoadingPhotos = true;
....
....
....
....
// Indicate new photos adding completed
window.isLoadingPhotos = false;
}
And,
$(window).scroll(function () {
var trigger = $(document).height() - 300;
if (trigger <= $(window).scrollTop() + $(window).height()) {
if(!window.isLoadingPhotos) {
//Call function to load next 10
loadNextPhotos();
}
}
});

Javascript - How do I improve performance when animating integers?

On the site I'm working on, we collect data from a datasource and present these in their own design element, in the form of an SVG. The SVG files are renamed to .php in order to insert the dynamic data from the datasource.
Then, I'm using inview javascript to initialize a function that animates the data from the source, from 0 to their actual value. However, I notice this gets kinda heavy on the browser, when there are a lot of elements that are running the animate function.
Is there perhaps a smarter way of doing this? I haven't really dug that much into it, because it's not that bad. I just happened to notice the lag when scrolling through the area being repainted.
Here's my js code:
$('.inview article').bind('inview', function(event, isInView, visiblePartX, visiblePartY) {
if (isInView) {
// element is now visible in the viewport
if (visiblePartY == 'top' || visiblePartY == 'both' || visiblePartY == 'bottom') {
var $this = $(this);
var element = $($this);
$this.addClass('active');
reinitializeText(element);
$this.unbind('inview');
// top part of element is visible
} else if (visiblePartY == 'bottom') {
} else {
}
} else {
}
});
function reinitializeText(element) {
var svg = element.find('svg');
var children = svg.children('.infographics_svg-text');
// If there is no class in svg file, search other elements for the class
if (children.length == 0) {
var children = element.find('.infographics_svg-text');
}
children.each(function (){
var step = this.textContent/100;
var round = false;
if (this.textContent.indexOf('.') !=-1) {
round = true;
}
animateText(this, 0, step, round);
});
}
function animateText(element, current, step, round) {
if (current > 100) return;
var num = current++ *step;
if (round) {
num = Math.round((num)*100)/100
} else {
num = Math.round(num);
}
element.textContent = num;
setTimeout(function() {
animateText(element, current, step, round);
}, 10);
}
Edit: Because of the difference in data values received from the source (low numbers to huge numbers), The speed of the animation is increased so it doesn't go on forever

Can i create a javascript carousel which contains a flash file as well as static images?

I was wondering if it's possible to include an swf within a javascript carousel that currently just contains stagic images. What I'm looking to do is include a flash animation within the carousel.
I guess I've got two main questions:
Is it possible to cycle through flash files in the same way as an image?
How would I get the javascript and flash to interact so the flash file would know when it had been selected?
If it helps, here's the js we're using:
$(document).ready(function(){
var $looper = true;
var timer;
var currentSlide = 0;
var cell = 0;
var row = 1;
var hCycles = 0;
var aCycles = 0;
//no. of full cycles
var homecycles = 2;
var aboutcycles = 2;
//aboutSlide speed
var fast = 1200;
var slow = 4000;
//hide homepage slides
$('#slide2').fadeOut(0);
$('#slide3').fadeOut(0);
$('#slide4').fadeOut(0);
$('#slide5').fadeOut(0);
$('#slide6').fadeOut(0);
//hide about slides
$('.a-slide1').fadeOut(0);
$('.a-slide2').fadeOut(0);
$('.a-slide3').fadeOut(0);
$('.a-slide4').fadeOut(0);
$('#slide-c1 .a-slide1').fadeIn(1200);
runSlide(fast);
function runSlide(x) {
if ($('body').is('.about')) {
setTimeout(function() {
aboutSlides();
}, x);
} else {
if ($looper) {
setTimeout(function() {
slideShow();
}, 4000);
}
}
}
function slideShow() {
if ($looper) {
if (currentSlide++ < 6 && hCycles < homecycles) {
$('#slide'+ currentSlide).fadeOut(1200);
if (currentSlide == 6) {
$('#slide1').fadeIn(1200);
$('#slide-wrapper li').removeClass('active');
$('#btn1').addClass('active');
currentSlide = 0;
hCycles = hCycles+1;
} else {
$('#slide'+ (currentSlide+1)).fadeIn(1200);
$('#slide-wrapper li').removeClass('active');
$('#btn'+ (currentSlide+1)).addClass('active');
}
runSlide();
} else {
$looper = false;
}
}
};
$('#slide-wrapper li').each(function(index) {
$('#btn'+(index+1)).click(function(){
$looper = false;
$('.slide').fadeOut(1200);
$('#slide'+ (index+1)).fadeIn(1200);
$('#slide-wrapper li').removeClass('active');
$(this).addClass('active');
});
});
function aboutSlides() {
if (cell++ < 3 && aCycles < aboutcycles) {
if (cell == 3) {
if (row < 3) {
row = row+1;
} else {
row = 1;
aCycles = aCycles+1;
}
var hide = (row-1);
if ((row-1) == 0) {hide = 3}
$('#slide-c1 .a-slide'+ hide).fadeOut(1200);
$('#slide-c1 .a-slide'+row).fadeIn(1200);
cell = 0;
runSlide(fast);
} else {
$('#slide-c'+(cell+1)+' .a-slide'+ (row-1)).fadeOut(1200);
$('#slide-c'+(cell+1)+' .a-slide'+(row)).fadeIn(1200);
if (cell == 2) {
runSlide(slow);
} else {
runSlide(fast);
}
}
} else {
// create the final strip
$('#slide-c3 .a-slide3').fadeOut(1200);
$('#slide-c3 .a-slide4').fadeIn(1200);
}
}
});
Thanks!
There isn't any problem as to whatever content you want to put in your slides. As long as it is valid html, it's valid in a slide. Countless jquery/motools/etc plugins let you specify whatever you want for content.
flash is valid.
But you might want to revert to another revealing method. setting the opacity on a swf from javascript is complex and yields to different results, according to browser and flash version. If your flash file is custom made, then you can create a function that fades it to white for example, and call it from javascript. But from experience, changing the opacity of a swf is calling for trouble.
I don't know if this is relevant enough to be an answer, I wanted to post it as a comment, but there isn't any comment button. Oh well.

Categories

Resources