I am working on some code that uses jQuery to parse data out of html documents from the web. This decision was made because jQuery, with its awesome ability to select objects on a page, makes it excellent for parsing.
The code works like this (where 'html_string' is the html of a whole web page):
var page = $(html_string);
The problem I am having is that javascript is being evaluated and executed within the html_string as well. This results in new threads being formed that in some cases, contain infinite loops that make repeated requests to the server and eventually crash the whole client-side of application (not the server).
Is there a way to somehow prevent the execution of javascript in this situation. In this situation, the execution of javascript is an unwanted side effect.
Thanks so much!
Here is a crappy little jsfiddle that shows you the js does not run when you load the html_string into $. When you click run you will see an immediate alert 'wtf'. Three seconds later, the html is loaded into $ and the body is updated to say 'moo', you should not see the alert.
http://jsfiddle.net/9BAkE/
One way would be to parse the html string befor you wrap it with jQuery.
Something like:
var page = html_string;
//then find the script tag (untested code)
int beginning_of_script = page.indexOf('<script>');
int end_of_script = page.indexOf('</script>');
// remove the script
page = page.remove(beginning_of_script, end_of_script);
You could load this syntax into the browser initially as a comment
<script>
/* var page = $(html_string); */
</script>
and then extract the contents of the comment later. The advantage here is that the browser is not going to parse and execute the comment on page load.
You can also explore using jQuery's .load() function, not sure if that will suit your needs.
If you donot care having one extra element, check this! http://jsfiddle.net/UbCFc/4/
Related
As the title says, if I remove a script tag from the DOM using:
$('#scriptid').remove();
Does the javascript itself remain in memory or is it cleaned?
Or... am I completely misunderstanding the way in which browsers treat javascript? Which is quite possible.
For those interested in my reason for asking see below:
I am moving some common javascript interactions from static script files into dynamically generated ones in PHP. Which are loaded on demand when a user requires them.
The reason for doing this is in order to move the logic serverside and and run a small script, returned from the server, clientside. Rather than have a large script which contains a huge amount of logic, clientside.
This is a similar approach to what facebook does...
Facebook talks frontend javascript
If we take a simple dialog for instance. Rather than generating the html in javascript, appending it to the dom, then using jqueryUI's dialog widget to load it, I am now doing the following.
Ajax request is made to dialog.php
Server generates html and javascript that is specific to this dialog then encodes them as JSON
JSON is returned to client.
HTML is appended to the <body> then once this is rendered, the javascript is also appended into the DOM.
The javascript is executed automatically upon insertion and the dynamic dialog opens up.
Doing this has reduced the amount of javasript on my page dramatically however I am concerned about clean up of the inserted javascript.
Obviously once the dialog has been closed it is removed from the DOM using jQuery:
$('#dialog').remove();
The javascript is appended with an ID and I also remove this from the DOM via the same method.
However, as stated above, does using jQuery's .remove() actually clean out the javascript from memory or does it simple remove the <script> element from the DOM?
If so, is there any way to clean this up?
No. Once a script is loaded, the objects and functions it defines are kept in memory. Removing a script element does not remove the objects it defines. This is in contrast to CSS files, where removing the element does remove the styles it defines. That's because the new styles can easily be reflowed. Can you imagine how hard it would be to work out what a script tag created and how to remove it?
EDIT: However, if you have a file that defines myFunction, then you add another script that redefines myFunction to something else, the new value will be kept. You can remove the old script tag if you want to keep the DOM clean, but that's all removing it does.
EDIT2: The only real way to "clean up" functions that I can think of is to have a JS file that basically calls delete window.myFunction for every possible object and function your other script files may define. For obvious reasons, this is a really bad idea.
If your scripts have already executed removing the DOM elements are not going to get rid of them. Go to any page with JavaScript, open up your preferred javascript console and type $("script").remove(). Everything keeps running.
And this demonstrates #Kolink answer:
http://jsfiddle.net/X2mk8/2/
HTML:
<div id="output"></div>
<script id="yourDynamicGeneratedScript">
function test(n) {
$output = $("#output")
$output.append("test " + n + "<br/>")
}
test(1);
</script>
Javascript:
$("script").remove();
// or $("#yourDynamicGeneratedScript").remove();
test(2);
test(3);
test(4);
function test(n) {
$output = $("#output")
$output.append("REDEFINED! " + n + "<br/>")
}
test(5);
test(6);
test(7);
I have a javascript file that needs to count how many classes (.wrapper) there are in a external html page.
So far i have been using this for a count (it was previously all on the same page).
var adCount = $('.wrapper').size();
alert(adCount);
But i can't seem to find anything that would allow me to run this statement on a different page than the code is runing on. I was hoping to add something like this.
var adCount = $('js/sliderExternal.html .wrapper').size();
alert(adCount);
They are in the same directory but I'm keeping the pages seperate as the external page needs to be updated constantly and i don't want it in the middle of a page of code. (This page may be updated by people who don't code at all). Anyway, any help on this would be much appreciated.
If you need any more information ask away!
Thanks.
This should work:
$.get('js/sliderExternal.html', function(data){
$(data).find('.wrapper').size();
})
Also see API Doc for $.get().
You would have to load the page into your html first using document.load() and append() it to your DOM structure. Once you do this you can use JQuery to find the number of classes within it.
Load that external html inside some div having visibility false.something like this:
$('#id_of_div').load(external_url)
and then find the length using:
var numItems = $('.wrapper').length
I have a webpage created by a php script that upon loading will contain 0 to N div elements. For each div I run a specific javascript code that manipulates data relevant to that div.
One of the things this code does is create an img element and set its 'src' attribute to a certain url of an image of a known (but variable) size. This is done for caching. Those images are not supposed to be displayed in the initial page layout - but each should appear after a certain user input (mouse hover) - so I'm trying to cache the images so it won't take long for them to appear.
The loading of the images of-course takes time - and each time an image loads the code blocks resulting in high load times. an example:
<div id="i1">
<script type="text/javascript">
/* run code relevant to 'i1', and amongst other things load some image
into a detached img element for later use. let's call this code 'bcode' */
</script>
<div id="i2">
<script type="text/javascript">
/* run 'bcode' for i2 */
</script>
<div id="...and so on">
To try having the code run asynchronously, I tried this:
<div id="i1">
(function() {
var asyncScriptElement = document.createElement('script');
asyncScriptElement.async = true;
var scriptText = document.createTextNode ('here I put all of the relevant "bcode"');
asyncScriptElement.appendChild (scriptText);
document.getElementById ('Img_1_2').appendChild (asyncScriptElement);
}());
It works under FF (still not fast enough), and it obviously doesn't work under IE.
Do you have any suggestion as to how to achieve this?
Also note, that I don't really need to get anything from another external php (i.e. to use XMLHttpRequest) - I got all the data I need in this php. I just need a way to make the loading of the images unblocking...
Looks like you need the waitfor/and construct provided by the apollo library: http://onilabs.com/stratifiedjs#waitfor-and
Javascript is single threaded and always runs synchronously.
There are browser extensions to get around this, notably the concept of Javascript Workers in Mozilla
I would wrap your scripts in an HTML page (eventually generated by PHP) and download it as an iframe to assure the same behaviour for any browser.
There are other more elegant options with pros and cons; here you can find a comparison of viable options, browser compatibility and a nice decision tree.
I have a web page that loads an external chat script, but the script loads before all my CSS and jQuery kick in, so my page looks all messed up for a few seconds. Need help figuring out how to launch my chat script once the page is done loading...I think it can be done by adding the script into my jQuery setup, but I'm not sure how to do that.
here's the code, it's self-explanatory enough not to be familiar with the actual software.
<script>
var online_text = "Chat Online Now";
var offline_text = "Chat Not Available";
var check_back = 1; // this lets the script check the operator status without being logged in
</script>
<script src="http://my.domain/chat/file.php"></script>
I think what happens is that the .php file will write my online or offline text with the necessary chat link, and that's why I have to put the script in the place where I want the chat text to display.
hope that makes sense...and hopefully the community can help me figure out how to solve the problem. thanks!
UPDATE: here's where I am so far, unfortunately the #chaticon element is empty, even if I replace the script with simple text. Using jQuery 1.4.2 by the way:
$(document).load(function() {
var online_text = 'Chat Online Now';
var offline_text = 'Chat Not Available';
var check_back = '1';
$("li#chaticon").html('<script type="text\/javascript" src="http:\/\/my.domain\/chat\/file.php"><\/script>');
});
Check out using the JQuery function $(document).ready().
It will hold off running until your entire document is loaded and ready to go.
$(document).ready(), which was previously mentioned, will only wait until the DOM is ready for manipulation (i.e., the node hierarchy has been fully constructed). This will not, however, wait until any additional resources (images, style sheets, etc.) have been loaded, which sounds like what you're wanting to do.
If you need all of these additional resources to be loaded first, then use $(document).load(). This will wait until all additional resources have finished loading (and hence the page will have been fully rendered).
Stephen,
As per Dave's advice of putting the $(document).ready() function on the page i.e:
$(document).ready(function() {
var online_text = "Chat Online Now";
var offline_text = "Chat Not Available";
var check_back = 1;
// do any other stuff here
});
also, make sure the js files are loaded at the bottom of the page, just ahead of the closing </body> tag and the css is loaded in the <head> tag. This may or may not sort the above issue, but is recognised as 'good practice' in terms of page configuration.
jim
thanks jmar777, I agree there's some re-evaluating that needs to be done here...the chat script is a mix of document.write, php/mysql and some dom-oriented stuff. Not worth toying with for hours.
So I ended up putting the code from my original post into a PHP function and returning it to a variable all the way at the top of the page, this way it would be written a little bit earlier than if it were written on the fly while my page were loading. And I made a few tiny tweaks to my CSS file so that the part of the page that was getting strange-looking while the chat script loaded wouldn't look as strange.
I'm trying to dynamically insert the Tweetmeme button using Javascript. I'm currently using jQuery throughout the site. Here's the script that I'm using. I basically want to cycle through all the blog entries with a class of journal-entry and append the following JavaScript to the end. This Javascript comes straight from tweetmeme.com. This doesn't work for me though and it has something to do with the code between append(). It doesn't like the second set of script tags.
<script type="text/javascript">
$(document).ready(function() {
$('.journal-entry').each(function(index) {
$(this).append('<script type="text/javascript" src="http://tweetmeme.com/i/scripts/button.js"></script>');
});
});
</script>
Any help is appreciated.
Thanks.
Don't do this.
Inserting <script> HTML content into the DOM is unreliable: it works subtly differently in different browsers, and jQuery won't protect you from the differences.
In particularly, writing innerHTML never causes a <script> element's content to execute, but subsequently moving the <script> element from where it is to a new parent (which is part of jQuery's append process) may cause the script to execute, but not always (it depends on the browser).
In any case, it'll never work, because looking at button.js, it is calling document.write(). That function only makes sense to call at initial document parsing time; if you call it from an event afterwards, the call will simply replace the entire page content, destroying your existing page. A script that calls document.write() can only be run at document load time, from inside the execution path of a <script> element. You can't include the script in dynamically-created content at all, because it's not designed for it.
(If it makes you feel any better, it's barely designed at all; the button.js script is a badly broken load of old crap, including improper URL-escaping—using escape instead of the correct encodeURIComponent—and missing HTML-escaping. You may be better off well away from these total idiots.)
The closing </script> in the string in your append(...) call is closing the overall <script>
Try splitting it up into two strings. E.g:
$(this).append('<script type="text/javascript" src="http://tweetmeme.com/i/scripts/button.js"></'+'script>');