Greetings
One of my clients javascript files is failing. I have found the reason, but the discovery has made me REALLY confused as I have never seen anything like it.
The issue is that when the browser reads through the script sources and enters a specific custom .js file which contains 543 lines of code, it only reads to line 502 which is this if (isValidWidthChange) { but what confuses me is that when I use developer tool in IE and firebug in FireFox and uses their script debug tool, when it hits line 502, the javascript is cut off like so - if (isValidWidthChan
if (isValidWidthChange) {
if (isValidWidthChan
Can anyone give me a logic explanation on WHY this happens?
I can say so much that I was adding a few things to the file, but I took a back-up of the original before starting, and this is actually the error which keeps occuring even after I set the website to use the original file again.
I have tried IISRESET a lot of times. I have tried copying the file from a healthy environment. I have cleared all the caches in my browsers and on the server. Yet it still appears.
I didn't develop it myself, it's a third party product. But this has never happened before.
Codesnippet of where the error occurs
(function($) {
// jQuery autoGrowInput plugin by James Padolsey
// See related thread: http://stackoverflow.com/questions/931207/is-there-a-jquery-autogrow-plugin-for-text-fields
$.fn.autoGrowInput = function(o) {
o = $.extend({
maxWidth: 1000,
minWidth: 0,
comfortZone: 70
}, o);
this.filter('input:text').each(function() {
var minWidth = o.minWidth || $(this).width(),
val = '',
input = $(this),
testSubject = $('<tester/>').css({
position: 'absolute',
top: -9999,
left: -9999,
width: 'auto',
fontSize: input.css('fontSize'),
fontFamily: input.css('fontFamily'),
fontWeight: input.css('fontWeight'),
letterSpacing: input.css('letterSpacing'),
whiteSpace: 'nowrap'
}),
check = function() {
if (val === (val = input.val())) { return; }
// Enter new content into testSubject
var escaped = val.replace(/&/g, '&').replace(/\s/g, ' ').replace(/</g, '<').replace(/>/g, '>');
testSubject.html(escaped);
// Calculate new width + whether to change
var testerWidth = testSubject.width(),
newWidth = (testerWidth + o.comfortZone) >= minWidth ? testerWidth + o.comfortZone : minWidth,
currentWidth = input.width(),
isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth)
|| (newWidth > minWidth && newWidth < o.maxWidth);
// Animate width
if (isValidWidthChange) { // This is where it stops
input.width(newWidth);
}
};
testSubject.insertAfter(input);
$(this).bind('keyup keydown blur update', check);
});
return this;
};
})(jQuery);
It's probably encoding issue, please make sure you don't have special characters in all the script;
Look on the characters near Owns and Rate, that characters will be ignored by the browser and the script will be cut off by the amount of them
/*
Mapping GUI to event types
Click - clickEvents
Purchase -purchaseEvents
Consume - consumeEvents
Recommended - clickedRecommended
Rendered - renderedEvents
Rate ײateEvents
Blacklist - blacklistEvents
Owns ׯwnsEvents
Total
*/
Is it possible for you to split the script into two parts? 543 lines is quite a lot of code, and I would be surprised if there are not at least some functions or modules which could be moved to a separate script.
As for debugging the issue, your symptoms would suggest that your server may have some kind of maximum content length. I know there are maximums (maxima?) for requests (there is something called maxAllowedContentLength, which is configurable), but I would be surprised if there was an upper limit on the size of files served. (Frankly that would be damn stupid, and would cause lots of problems but hey, IIS is not always smart - or maybe your administrator has been a bit too parsimonious?). It would be interesting to check if the maximum is a matter of lines or (more likely) bytes. So, to check this, have you tried:
Adding comments - does this shift the
break-off point?
Adding additional
(unused) code - does this shift the
break-off point?
Serving another long
script, for example you could get a
hold of the developer version of
jQuery (rather than the minified
one). Does this get broken-off too?
The results of these experiments and similar would help narrow down the issue a little.
Related
I have more than 20 js files like jQuery etc in my project, when I scroll it gets hung as it loads very lazily. How to find which file creates the problem?
It may be one of several things and without looking at your code I couldn't possibly say what the cause would actually be. You've asked an extremely subjective comment. There's no silver bullet when it comes to debugging and problem solving.
I've always found the Occams Razor approach the most effective.
"When you remove all other options, whatever remains, however unlikely, must be the problem/solution/answer."
Firstly, before you start removing JS files, have you tried doing a full-search of your project for .scroll? There's a high likelihood that there are several functions which run on-scroll which are causing reflows, a common problem which such code.
Once you've assessed your code, you can verify exactly what happens when the code executes using the "Performance" tab in Google Chrome to do this (Learn how to use the Performance Tab here). You can take the appropriate action.
Assuming that your code suffers from the same problem I've encountered in my formative years using jQuery - multiple or problematic on-scroll events - you can de-bounce the ones which can run after scrolling has completed. You can do this by using the following pattern.
Scenario 1:
This would run many times. 'N' times for each scrollwheel drag (dependent on settings - mine is 10) and even more times when using the scrollbar.
function someFunc() {
let someArr = [];
for(var i = 0; i < 1000000; i++ {
someArr.push((i * 2));
}
for(var i = 0; i < someArr.length; i++ {
someArr[i] /= 0.25;
}
}
$(window).on("scroll", function() {
someFunc();
});
Scenario 2:
This would run once after scrolling has finished. Waiting for 200ms before executing to ensure the user has completely finishing scrolling.
function someFunc() {
let someArr = [];
for(var i = 0; i < 1000000; i++ {
someArr.push((i * 2));
}
for(var i = 0; i < someArr.length; i++ {
someArr[i] /= 0.25;
}
}
let debouncedTimeout = null;
$(window).on("scroll", function() {
if (debouncedTimeout) {
clearTimeout(debouncedTimeout);
}
debouncedTimeout = setTimeout(someFunc(), 200);
});
Add a console.log("Check") with numbers (check1, check2) and so on in every file. Check your console in your browser, look in which series they load in console. If it takes a while to load the next log you know its the previous file with the number you logged.
Your console should say everything.
But loading so many js files is bad practice.
Try to fit everything in to one, so in further bckend development can go to an .min.js
But if you keep doing this. The simplest way is to keep track of the funcioncesequences with console.log, so that you evrything works how it is supposed to
:)
Short Question
How can I (as reliably as possible) calculate the time when "above the fold" content is visually complete, including external CSS and fonts being applied and any images loaded.
Full Question
Apologies there is a lot to this question, I just wanted to show I had worked on the question and where I was at so it didn't end up as a "how do I do this" type question and get insta closed!!
I am attempting to try and work out if all resources required to render "above the fold" content have been fully downloaded in the client browser.
This is part of a bigger goal of simulating SpeedIndex purely using browser APIs (i.e. not using a screenshot timeline).
What I need to gather
All of the elements that appear above the fold on a page.
Ensure that all relevant assets have loaded.
Additionally this data is being sent to the server for analysis so I want to try and keep it at one request if possible.
Challenges I can't overcome
Having to run the function that gets the elements above the fold more than once
Ensuring that all critical assets are actually loaded on a very slow connection.
Making sure the function does run if network traffic is high, if there is never a quiet 2 second window on the network (maybe due to an old fashioned chat that polls the server every second) it will never fire.
Firstly this doesn't have to be perfect, it is an approximation, but the more accurate I can make it the better!
The way I am doing it at the moment is using PerformanceObserver to list all resources as they are downloaded.
The second I get a 2 second window where no requests have been completed I assume critical CSS has been downloaded and start looking at the images on the page.
//getRects is the function to get all of the rectangles above the fold.
var rectInterval = setTimeout(getRects, 2500);
var xx = new PerformanceObserver(function (ll, p) {
ll.getEntries().forEach(function (en) {
if (en.name.indexOf(apiEndpoint) == -1) {
if (en.entryType == "layout-shift") {
if (en.entryType == "resource"){
//any resources I reset the timer waiting for a quiet time
clearTimeout(rectInterval);
rectInterval = setTimeout(getRects, 2000);
}
}
});
});
xx.observe({
entryTypes: ['largest-contentful-paint', 'longtask', 'resource', 'paint', 'navigation', 'mark', 'measure', 'layout-shift', 'first-input']
});
I grab the dimensions of all images and elements with background images on the page in the function getRects using getBoundingRect() and then calculate if they appear above the fold using window.innerHeight etc.
These are the candidates to check when they downloaded (along with the previous list of resources etc.)
var doc = window.document;
var browserWidth = window.innerWidth || doc.documentElement.clientWidth;
var browserHeight = window.innerHeight || doc.documentElement.clientHeight;
function checkRectangle(el){
var rtrn = false;
if (el.getBoundingClientRect) {
var rect = el.getBoundingClientRect();
//check if the bottom is above the top to ensure the element has height, same for width.
//Then the last 4 checks are to see if the element is in the above the fold viewport.
if (rect.bottom <= rect.top || rect.right <= rect.left || rect.right < 0 || rect.left > browserWidth || rect.bottom < 0 || rect.top > browserHeight) {
rtrn = false;
}else{
rtrn = {};
rtrn.bot = rect.bottom;
rtrn.top = rect.top;
rtrn.left = rect.left;
rtrn.right = rect.right;
}
}
return rtrn;
}
//function to get the rectangles above the fold
function getRects(){
var rects = [];
var elements = doc.getElementsByTagName('*');
var re = /url\(.*(http.*)\)/ig;
for (var i = 0; i < elements.length; i++) {
var el = elements[i];
var style = getComputedStyle(el);
if(el.tagName == "IMG"){
var rect = checkRectangle(el);
if(rect){
//The URL is stored here for later processing where I match performance timings to the element, it is not relevant other than to show why I convert the `getBoundingClientRect()` to a simple object.
rect.url = el.src;
rects.push(rect);
}
}
//I also need to check for background images set in either CSS or with inline styles.
if (style['background-image']) {
var rect = checkRectangle(el);
if(rect){
var matches = re.exec(style['background-image']);
if (matches && matches.length > 1){
rect.url = matches[1].replace('"', '');
rects.push(rect);
}
}
}
}
That bit is fine (although any tips to narrow the search so I am not looping over everything would be great) but my problem comes on a slow loading website. If there is more than a 2 second gap between requests (which can happen on a particularly slow connection or if the server is a long way from the user) then I won't get complete data.
My workaround was to then monitor for further network requests (yet again waiting for a 2 second delay between requests) and re-run the function to gather the above the fold content. This obviously does not work well if the site uses lazy loading on scroll as requests can keep firing throughout the page lifecycle.
As gathering the dimensions of the elements can be quite CPU intensive on a very heavy page, coupled with the need to send this data to the server for analysis, I am trying to find a more robust way of ensuring all critical content is loaded. or a way to only fire getRect once but ensure all initial loading is complete.
Presume that any manipulation of data can be done later on the server if the payload is small enough (less than 1kb say)
Things I have considered
Looking for any <links>, <scripts> etc. and checking they have loaded. The problem comes with dynamically added links as well as external resources (i.e. stylesheets linked within another stylesheet). This would probably be more robust but would become very complex.
Setting the time between checks (the quiet time I am waiting for) to be higher. This obviously makes the problem of a traffic heavy website worse as the "quiet time" may never occur.
Using MutationObserver to monitor the page and yet again waiting for quiet time. However this would get fired more often if the page had any interactivity as far as I can tell?
I am aware that my method will over report for sites that have correctly inlined their CSS, that is not a problem.
Am I on the right track as a way of solving this conundrum, or is there some easy formula I can use based on window.performance data (or similar API) that lets me say "all above the fold elements are loaded and rendered."
I hope that is clear but any questions just ask as I know there is a lot in this question to answer simply "how do I check all critical resources have loaded".
My problem is the following.
I am attempting to connect the compressor.reduction.value of the compressor node to a div's height so I can monitor the compression reduction effect dynamically. This works fine. The problem is when the audio signal stops the div freezes at its current position. I would like the div to not freeze and have it's height go to zero. The way I fixed this is by using a setInterval that checks for the height of the div and if it remains at exactly the same height for more than a few seconds then the display is set to none effectively hiding the div. Now my question is two fold. First, if there is a better way to do this please share, but irrespective there is one little thing that is irking me that I can't figure out. When I write the code as such it works. However, it looks a bit ugly since the compressor node is outside the play function..........
var compressor = audioContext.createDynamicsCompressor();
soundObj.play = function() {
$(".compression-meter").css("display", "block");
var playSound = audioContext.createBufferSource();
compressor.threshold.value = -40;
compressor.ratio.value = 20;
playSound.buffer = soundObj.soundToPlay;
playSound.connect(compressor);
compressor.connect(audioContext.destination)
playSound.start(audioContext.currentTime);
compReductionMeter()
}
/*______________ Compressor metering __________*/
var cachedMeterValue = null
function compReductionMeter() {
cachedMeterValue = $(".compression-meter").height()
var reduction = compressor.reduction.value;
var bar = $(".compression-meter");
bar.height((-1 * reduction) + '%');
requestAnimationFrame(compReductionMeter);
};
window.setInterval(function() {
if ($(".compression-meter").height() == cachedMeterValue) {
console.log("checking compression meter height when matched with cachedMeterValue.It is " + $(".compression-meter").height())
$(".compression-meter").css("display", "none")
}
}, 2000);
When I write the code like this the div doesn't even appear and I am not sure why. From my view it "should" work and I really want to know why it doesn't and what I'm missing.
soundObj.play = function() {
$(".compression-meter").css("display", "block");
var playSound = audioContext.createBufferSource();
var compressor = audioContext.createDynamicsCompressor(); // modified placement
compressor.threshold.value = -40;
compressor.ratio.value = 20;
playSound.buffer = soundObj.soundToPlay;
playSound.connect(compressor);
compressor.connect(audioContext.destination)
playSound.start(audioContext.currentTime);
compReductionMeter(compressor.reduction.value) // modified - added argument
}
/*______________ Compressor metering __________*/
var cachedMeterValue = null
function compReductionMeter(compVal) { // modified - added parameter
cachedMeterValue = $(".compression-meter").height()
var reduction = compVal; // modified - is now param value
var bar = $(".compression-meter");
bar.height((-1 * reduction) + '%');
requestAnimationFrame(compReductionMeter);
};
window.setInterval(function() {
if ($(".compression-meter").height() == cachedMeterValue) {
console.log("checking compression meter height when matched with cachedMeterValue.It is " + $(".compression-meter").height())
$(".compression-meter").css("display", "none")
}
}, 2000);
Thank you.
This annoyance in DynamicsComporessorNode will be fixed at Chrome version M40.
https://codereview.chromium.org/645853010/
Unfortunately, the current design of DynamicCompressorNode keeps the gain reduction value from being updated when the stream from source node stops. That is, the GR value is only being updated when the active audio stream is running. AnalyserNode has the very same issue.
If your audio graph is simply using a single source node, you can use .onended event from the source node to zero the height of DIV. However, if you rather have a complex audio graph, then it is going to be a bit more involved.
http://www.w3.org/TR/webaudio/#dfn-onended_AudioBufferSourceNode
Here is a possible hack to get zeroes to the compressor and analyzer. Create a new buffer of all zeroes. Assign that to a new AudioBufferSourceNode. Connect this node to the compressor and/or analyser and schedule the source to start when your source ends (or slightly before). This should keep the compressor/analyser node processing so the GR value and analyser node to drop to zero.
I didn't actually try this.
First I have to say that I am not a professional programmer but designer learning by doing. So I am afraid I need simple explanations if possible.
I am using Edge animate as parts of a website with the help of a particular script (by Andrew Trice, see here: http://www.tricedesigns.com/2012/07/12/using-adobe-edge-animations-as-components/ ). I also succeeded in storing only 1 Edge preload.js file in my libs folder. In it I introduced a variable at the end in order to be able to load Edge animations one after another. Code:
function setupAnimationView( template ) {
var $workPage = $("#workPage")
$workPage.empty();
window.AdobeEdge = undefined;
AdobeEdge = undefined;
var viewModel = { workChart: workChart };
var html = Mustache.to_html(template, viewModel)
$workPage.append( html );
//detect if edge is loaded yet
var edgeDetectionFunction = function() {
if ( AdobeEdge && AdobeEdge.compositions != undefined ) {
//put a delay here
var hasComposition = false;
if ( AdobeEdge.compositions ) {
//loop to see if the composition is actually loaded
for ( var key in AdobeEdge.compositionDefns ) {
hasComposition = true;
break;
}
}
if ( hasComposition ) {
setTimeout( function() {
$(window).trigger( "animationReady" ); }, 100 );
return;
}
}
else if ( AdobeEdge ) {
window.onDocLoaded();
}
setTimeout( edgeDetectionFunction, 100 );
}
edgeDetectionFunction();
}
Modified Adobe Edge preload.js:
...
requiresSVG=false;
doDelayLoad=false;
htFallbacks={
};
aLoader = [
{ load: "libs/jquery-1.10.2.min.js"},
{ load: "libs/jquery.easing.1.3.js"},
{ load: "libs/jquery.rotate.js"},
{ load: "libs/edge.1.0.0.min.js"},
{test: !hasJSON, yep:"libs/json2_min.js"},
{ load: "templates/Chart_" + workChart + "/Page_work_edge.js"},
{ load: "templates/Chart_" + workChart + "/Page_work_edgeActions.js"}];
loadResources(aLoader, doDelayLoad);
preContent={dom:[
]}
;//simpleContent
dlContent={dom: [
]}
;//simpleContent
//updated paths for loader
//added this so it can be invoked later
window.onDocLoaded = onDocLoaded;
})( "animation_content");
So far thanks to Andrew everything works very fine except that I saw in my developer tool (Safari) that my code leads to loading the basic js files like jquery-1.10.2.min.js over and over again each time a new animation starts to run and this files are summing up to an endless number… which I guess isn’t a good thing.
I even understand why (at least I believed) and so I deleted the respective lines in the aLoader object at the end of preload. (of course they are loaded within the script tag in my index page)
aLoader = [
{ load: "libs/jquery-1.10.2.min.js"}, // deleted this one
{ load: "libs/jquery.easing.1.3.js"}, // deleted this one
{ load: "libs/jquery.rotate.js"}, // deleted this one
{ load: "libs/edge.1.0.0.min.js"}, // deleted this one
{test: !hasJSON, yep:"libs/json2_min.js"},
{ load: "templates/Chart_" + workChart + "/Page_work_edge.js"},
{ load: "templates/Chart_" + workChart + "/Page_work_edgeActions.js"}];
because I can’t see why it would be necessary to load them more than once. Yet, after doing so only the first animation runs, the second does not any longer. But why? I checked in the browser and see that jquery-1.10.2.min.js is in the page so why can’t (or seems so) the Edge files use it any longer? The same for the other ones (rotate etc.).
I also tried to suppress these two lines from the function above:
window.AdobeEdge = undefined;
AdobeEdge = undefined;
without any result though.
Where is the trick to avoid reloading those basic needed .js files? Any ideas? Thank you so much for advice
Garavani
#Jamie
EDIT:
So ,hello Jamie! I was so curious about your solution that I dropped everything else and tried it. Sadly it does not work in the situation I tried to explain as exactly as possible in the lines above this edit.
To avoid any misunderstandings here my changed code following your instructions (very good explanation by the way!):
edgePreload.js (in my version it has no filename addition and lies in my „lib“ folder that is accessed by each new animation after the method by Andrew - see above!) :
window.AdobeEdge = window.AdobeEdge || {};
window.AdobeEdge.$_ = $;
// Include yepnope
if(!AdobeEdge.yepnope) {…
Then further on:
$(function() { // your insert opening function
(function(compId){
var htFallbacks; …
…
window.onDocLoaded = onDocLoaded;
})( "animation_content");
}); // your insert closure
My index.html contains the following scripts (among others):
<script src="libs/jquery-1.11.0.min.js"></script>
<script src="libs/jquery.easing.1.3.js"></script>
<script src="libs/jquery.rotate.js"></script>
<script src="libs/edge.1.0.0.min.js"></script>
<script src="libs/mustache.js"></script>
<script src="libs/mustacheHelper.js"></script>
which I like to host on my server. (avoiding all kinds of trouble coming up with versions updates not under my control)
Now I dared and hoped to be able to cancel that stuff from my aLoader arrow as follows:
aLoader = [
// { load: "libs/jquery-1.11.0.min.js"},
// { load: "libs/jquery.easing.1.3.js"},
// { load: "libs/jquery.rotate.js"},
// { load: "libs/edge.1.0.0.min.js"},
{test: !hasJSON, yep:"libs/json2_min.js"},
{ load: "templates/Chart_" + workChart + "/Page_work_edge.js"},
{ load: "templates/Chart_" + workChart + "/Page_work_edgeActions.js"}];
but id t doesn’t work (throwing all kinds of errors obviously based on lacking edge codes).
When I replace all in the aLoader again at least it works without showing errors concerning the new inserted lines. But I have no result. Yet, would be soooooooooo cool!!!
Did I miss something? Did you really check thoroughly what I did in my initial lines above?
I am curious to hear your ideas!
Thank you so far for your interest and willing to share your knowledge of this complicated edge material (not much discussed - for good reasons I guess – here in stack overflow).
I've been having the exact issue and you've probably solved it by now, but hopefully it'll help someone else.
1) Make sure you get your files by choosing 'HTML' in your publish settings, and publishing to a clean folder.
2) Use a prettifier tool (e.g. http://jsbeautifier.org/) to make the [filename]_edgePreload.js file readable.
3) Add this line window.AdobeEdge.$_ = $; just under the top line window.AdobeEdge = window.AdobeEdge || {};
4) Find this line (function(compId) { (which is the start of the load method) and wrap that whole method (everything between here and the bottom of the page) with $(function() { and });
5) In the aLoader array, remove the first two entries that specify how to load edge and jquery.
6) Add the edge library (currently https://animate.adobe.com/runtime/4.0.1/edge.4.0.1.min.js) to the head of your site, along with jQuery.
Don't feel too bad that this was confusing, the Adobe Edge output code has been written by a cabbage with legs. Everyone struggles with it :)
Here's a conundrum I've discovered.
I have a script that opens a file in InDesign, does some work to it, then closes it. To help speed it up, I have turned off displaying the file by using the false argument while opening the file, like so:
var document = app.open(oFile, false);
Sometimes, while doing some work on an open file, the script may need to need to resize a certain page from 11 inches tall to 12.5 inches tall, thusly:
if (padPrinted) {
for (var p = 0; p < outputRangeArray.length; p++) {
var padPage = document.pages.item(outputRangeArray[p]);
if (padPage.bounds[2] - padPage.bounds[0] === 11) {
padPage.select();
var myY1 = padPage.bounds[0] -= 0.75;
var myX1 = padPage.bounds[1];
var myY2 = padPage.bounds[2] += 0.75;
var myX2 = padPage.bounds[3];
padPage.reframe(CoordinateSpaces.INNER_COORDINATES, [[myX1*72, myY1*72], [myX2*72, myY2*72]]);
}
}
}
This has been working flawlessly for me for quite some time, but now it sometimes errors on the line padPage.select() with the message:
No document windows are open.
If I go back to the line which opens the file and delete the false argument, then the script works fine.
So, I'd like to know if there's any way to get around this. I'd like to have the documents open without displaying them, but still have the ability to resize a page when I need to. Any ideas?
Why do you call padPage.select();? It doesn't look like your code needs it.
Edit:
On page to page 42 of the Adobe InDesign CS6 Scripting Guide: Javascript, there is a sample snippet that reframes the page and doesn't call select(). The snippet comes from a sample script in the InDesign CS6 Scripting SDK (scroll to the bottom).
The path of the sample script is Adobe InDesign CS6 Scripting SDK\indesign\scriptingguide\scripts\JavaScript\documents\PageReframe.jsx
Inspecting this script, we see that it never calls select(). In fact, the PageResize.jsx never calls select() either.
Also, while InDesign Server can resize and reframe pages, you'll notice that the select() function is missing entirely. It would seem that select() affects only the GUI.
In the face of all this evidence, I would wager that the scripting guide is wrong when it says "you must select the page". Try removing that line and see if it works.
Edit 2
On an unrelated note, the following lines might be troublesome:
var myY1 = padPage.bounds[0] -= 0.75;
var myX1 = padPage.bounds[1];
var myY2 = padPage.bounds[2] += 0.75;
The += and -= operators will attempt to modify the bounds directly, but the bounds are read-only and can only be modified with methods such as resize or reframe. I would recommend changing it to this:
var myY1 = padPage.bounds[0] - 0.75;
var myX1 = padPage.bounds[1];
var myY2 = padPage.bounds[2] + 0.75;