Hi, I have been spending a lot of time reading Prototype.js. Because there are no comments, I don''t understand the rational for why it is doing a few things. Two things are in Element.update update: function(element, html) { $(element).innerHTML = html.stripScripts(); setTimeout(function() {html.evalScripts()}, 10); }, Why strip the scripts before inserting? Is this only for NS6 browser support? Why wait 10 ms before evaluating the scripts? Thanks, Peter
Bauser, Joseph (Joe)
2006-Jul-21 14:18 UTC
RE: Prototype.js strips scripts before innerHTML
I can''t answer for the first, but I believe the 10ms wait is in some way related to the fact that not all browsers update the DOM immediately after an innerHTML assignment. The timeout is probably just giving time for that update to happen. -----Original Message----- From: rails-spinoffs-bounces-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org [mailto:rails-spinoffs-bounces-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org]On Behalf Of Peter Michaux Sent: Friday, July 21, 2006 10:07 AM To: rails-spinoffs-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org Subject: [Rails-spinoffs] Prototype.js strips scripts before innerHTML Hi, I have been spending a lot of time reading Prototype.js. Because there are no comments, I don''t understand the rational for why it is doing a few things. Two things are in Element.update update: function(element, html) { $(element).innerHTML = html.stripScripts(); setTimeout(function() {html.evalScripts()}, 10); }, Why strip the scripts before inserting? Is this only for NS6 browser support? Why wait 10 ms before evaluating the scripts? Thanks, Peter _______________________________________________ Rails-spinoffs mailing list Rails-spinoffs-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs
scripts inserted via innerHTML are not executed, so this ensures any scripts actually get executed... does anyone else have the scientific answer for the timeOut? prevent UI blocking as much as possible? There are potential benefits, but it''s probably not 100% necessary. On 7/21/06, Peter Michaux <petermichaux-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> > Hi, > > I have been spending a lot of time reading Prototype.js. Because there > are no comments, I don''t understand the rational for why it is doing a > few things. Two things are in Element.update > > update: function(element, html) { > $(element).innerHTML = html.stripScripts(); > setTimeout(function() {html.evalScripts()}, 10); > }, > > > Why strip the scripts before inserting? Is this only for NS6 browser > support? > > Why wait 10 ms before evaluating the scripts? > > Thanks, > Peter > _______________________________________________ > Rails-spinoffs mailing list > Rails-spinoffs-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs >_______________________________________________ Rails-spinoffs mailing list Rails-spinoffs-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs
On 7/21/06, Ryan Gahl <ryan.gahl-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> scripts inserted via innerHTML are not executed, so this ensures any scripts > actually get executedThe scripts are evaluated when the timeout expires. What I''m interested in is why they need to be stripped when the HTML is inserted. Most browsers don''t care if the script elements are inside the html when using innerHTML. Netscape 6 automatically evaluates scripts when using innerHTML. It is the only browser I know of that does this. I wonder if that is the reason the scripts are stripped. Netscape 6 is pretty old now. I''m curious if there is another reason I don''t know of. Thanks, Peter
Peter Michaux wrote:> On 7/21/06, Ryan Gahl <ryan.gahl-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: >> scripts inserted via innerHTML are not executed, so this ensures any >> scripts >> actually get executed > > The scripts are evaluated when the timeout expires. What I''m > interested in is why they need to be stripped when the HTML is > inserted. Most browsers don''t care if the script elements are inside > the html when using innerHTML. > > Netscape 6 automatically evaluates scripts when using innerHTML. It is > the only browser I know of that does this. I wonder if that is the > reason the scripts are stripped. Netscape 6 is pretty old now.That sounds like a reasonable reason to me: Strip them off so some browsers don''t execute them, since others browsers won''t. Then execute with a delay since other browsers won''t update the DOM right away. Now it could be made slightly faster if you handled it differently for each browser, but since there''s a simple way that works for all of them I can see why it was done that way. -- Michael Peters Developer Plus Three, LP
Peter Michaux wrote:> update: function(element, html) { > $(element).innerHTML = html.stripScripts(); > setTimeout(function() {html.evalScripts()}, 10); > }, > > > Why strip the scripts before inserting? Is this only for NS6 browser > support?As another poster said scripts inserted via a innerHTML are not automatically executed so they will have to be manually executed. The reason for stripping them before inserting the content seems to have two reasons (in my opinion): * Ensures your DOM does not get messy. There does not seem to be any purpose in inserting the script node into the DOM so might as well remove it first to keep your DOM clean. That way if you want to traverse the DOM you don''t have to avoid script nodes. * It seems like relying on the browser to not execute the script is fragile. Maybe some browser will auto-execute the code at some point in the future. Since we are executing it manually might as well take the time to remove the possibility of it ever being executed more than once.> Why wait 10 ms before evaluating the scripts?This has to do with many browser''s threading model. From what I have read (and experienced) many browsers do not have a very good threading models in JavaScript. Basically once some JavaScript code is running all other threads of execution are on hold until the running thread is finished with it''s task. This includes whatever thread of execution that updates the DOM model when new content is inserted via innerHTML. For example if you do: foo.innerHTML = ''<span id="bar">Baz</span>''; var bar = document.getElementById(''bar''); This code will sometimes fail because although you added the content via innerHTML the DOM may not have been updated and therefore the "bar" element does not exist in the DOM yet. To work around this you can do: foo.innerHTML = ''<span id="bar">Baz</span>''; setTimeout(function() {var bar = document.getElementById(''bar'');}, 10); This will work because in 10 milliseconds whatever event handler is running will have finished, the DOM will update, then the callback will execute and have no problem accessing the DOM element. The actual delay time is not really important because the innerHTML action happens before the setTimeout method causing the DOM update to be appended to the list of threads waiting for their turn before the callback is appended to the list of threads waiting for their turn. Therefore the DOM update should always occur before the timeout is executed. All of this is similar to the "DoEvents" method in VB if you have ever used that to cause an interface to update while some long-running process is executing. It all stems from a light-weight threading model and is really just a workaround. Eric
Eric, Thank you. I was thinking similar ideas to what you wrote but just speculating about Sam''s thinking for all these things is a little strange. Peter On 7/21/06, Eric Anderson <eric-ANzg6odk14w@public.gmane.org> wrote:> Peter Michaux wrote: > > update: function(element, html) { > > $(element).innerHTML = html.stripScripts(); > > setTimeout(function() {html.evalScripts()}, 10); > > }, > > > > > > Why strip the scripts before inserting? Is this only for NS6 browser > > support? > > As another poster said scripts inserted via a innerHTML are not > automatically executed so they will have to be manually executed. The > reason for stripping them before inserting the content seems to have two > reasons (in my opinion): > > * Ensures your DOM does not get messy. There does not seem to be any > purpose in inserting the script node into the DOM so might as well > remove it first to keep your DOM clean. That way if you want to traverse > the DOM you don''t have to avoid script nodes. > > * It seems like relying on the browser to not execute the script is > fragile. Maybe some browser will auto-execute the code at some point in > the future. Since we are executing it manually might as well take the > time to remove the possibility of it ever being executed more than once. > > > Why wait 10 ms before evaluating the scripts? > > This has to do with many browser''s threading model. From what I have > read (and experienced) many browsers do not have a very good threading > models in JavaScript. Basically once some JavaScript code is running all > other threads of execution are on hold until the running thread is > finished with it''s task. This includes whatever thread of execution that > updates the DOM model when new content is inserted via innerHTML. For > example if you do: > > foo.innerHTML = ''<span id="bar">Baz</span>''; > var bar = document.getElementById(''bar''); > > This code will sometimes fail because although you added the content via > innerHTML the DOM may not have been updated and therefore the "bar" > element does not exist in the DOM yet. To work around this you can do: > > foo.innerHTML = ''<span id="bar">Baz</span>''; > setTimeout(function() {var bar = document.getElementById(''bar'');}, 10); > > This will work because in 10 milliseconds whatever event handler is > running will have finished, the DOM will update, then the callback will > execute and have no problem accessing the DOM element. > > The actual delay time is not really important because the innerHTML > action happens before the setTimeout method causing the DOM update to be > appended to the list of threads waiting for their turn before the > callback is appended to the list of threads waiting for their turn. > Therefore the DOM update should always occur before the timeout is executed. > > All of this is similar to the "DoEvents" method in VB if you have ever > used that to cause an interface to update while some long-running > process is executing. It all stems from a light-weight threading model > and is really just a workaround. > > Eric > > _______________________________________________ > Rails-spinoffs mailing list > Rails-spinoffs-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs >
AFAIK the setTimeout makes sure that the eval() is executed in the window-global context, and not the local execution context of the method it happens to be in. -Thomas Am 21.07.2006 um 16:19 schrieb Ryan Gahl:> scripts inserted via innerHTML are not executed, so this ensures > any scripts actually get executed... does anyone else have the > scientific answer for the timeOut? prevent UI blocking as much as > possible? There are potential benefits, but it''s probably not 100% > necessary. > > On 7/21/06, Peter Michaux <petermichaux-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > Hi, > > I have been spending a lot of time reading Prototype.js. Because there > are no comments, I don''t understand the rational for why it is doing a > few things. Two things are in Element.update > > update: function(element, html) { > $(element).innerHTML = html.stripScripts(); > setTimeout(function() {html.evalScripts()}, 10); > }, > > > Why strip the scripts before inserting? Is this only for NS6 > browser support? > > Why wait 10 ms before evaluating the scripts? > > Thanks, > Peter > _______________________________________________ > Rails-spinoffs mailing list > Rails-spinoffs-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs > > _______________________________________________ > Rails-spinoffs mailing list > Rails-spinoffs-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs-- Thomas Fuchs wollzelle http://www.wollzelle.com questentier on AIM madrobby on irc.freenode.net http://www.fluxiom.com :: online digital asset management http://script.aculo.us :: Web 2.0 JavaScript http://mir.aculo.us :: Where no web developer has gone before _______________________________________________ Rails-spinoffs mailing list Rails-spinoffs-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs
There we go, that sounds scientific :-) btw, Thomas, have you anything to say (maybe in a new thread), regarding what we''ve been so hotly debating here these last few days? ie. future of proto? On 7/21/06, Thomas Fuchs <t.fuchs-moWQItti3gBl57MIdRCFDg@public.gmane.org> wrote:> > AFAIK the setTimeout makes sure that the eval() is executed in the > window-global context, and not the local execution context of the method > it happens to be in. > -Thomas > > Am 21.07.2006 um 16:19 schrieb Ryan Gahl: > > scripts inserted via innerHTML are not executed, so this ensures any > scripts actually get executed... does anyone else have the scientific answer > for the timeOut? prevent UI blocking as much as possible? There are > potential benefits, but it''s probably not 100% necessary. > > On 7/21/06, Peter Michaux <petermichaux-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: > > > > Hi, > > > > I have been spending a lot of time reading Prototype.js. Because there > > are no comments, I don''t understand the rational for why it is doing a > > few things. Two things are in Element.update > > > > update: function(element, html) { > > $(element).innerHTML = html.stripScripts(); > > setTimeout(function() {html.evalScripts()}, 10); > > }, > > > > > > Why strip the scripts before inserting? Is this only for NS6 browser > > support? > > > > Why wait 10 ms before evaluating the scripts? > > > > Thanks, > > Peter > > _______________________________________________ > > Rails-spinoffs mailing list > > Rails-spinoffs-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > > http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs > > > > _______________________________________________ > Rails-spinoffs mailing list > Rails-spinoffs-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs > > > -- > Thomas Fuchs > wollzelle > > http://www.wollzelle.com > > questentier on AIM > madrobby on irc.freenode.net > > http://www.fluxiom.com :: online digital asset management > http://script.aculo.us :: Web 2.0 JavaScript > http://mir.aculo.us :: Where no web developer has gone before > > > > > > _______________________________________________ > Rails-spinoffs mailing list > Rails-spinoffs-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs > > >_______________________________________________ Rails-spinoffs mailing list Rails-spinoffs-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs
Thomas Fuchs wrote:> AFAIK the setTimeout makes sure that the eval() is executed in the > window-global context, > and not the local execution context of the method it happens to be in.Won''t it still execute in the local context because of the closure. That is of course while the "html" identifier is still available to be evaluated. Not trying to doubt your statement (as you know much more about prototype than I do), just trying understand better. Thanks, Eric
On 7/21/06, Eric Anderson <eric-ANzg6odk14w@public.gmane.org> wrote:> Thomas Fuchs wrote: > > AFAIK the setTimeout makes sure that the eval() is executed in the > > window-global context, > > and not the local execution context of the method it happens to be in. > > Won''t it still execute in the local context because of the closure. That > is of course while the "html" identifier is still available to be evaluated.The closure idea doesn''t apply if the code argument to setTimeout(code, delay) is a string. To paraphase Flanagan JavaScript 4th ed page 679: The statements in the string of setTimeout() execute in the context of window. Nowadays the code argument can also be a function which is how Prototype.js is using evalScripts(). Copying from this link http://groups.google.com/group/comp.lang.javascript/tree/browse_frm/thread/6db7df20ac5c9a08/529bb25a7e5456aa?rnum=1&q=settimeout+function+argument&_done=%2Fgroup%2Fcomp.lang.javascript%2Fbrowse_frm%2Fthread%2F6db7df20ac5c9a08%2F312e04763fb3ee4c%3Flnk%3Dgst%26q%3Dsettimeout+function+argument%26rnum%3D1%26#doc_312e04763fb3ee4c [start copy] If the first argument to setTimeout (or setInterval) is a string, the code is parsed and executed in the global scope and with "this" referring to the global object. If you change the first argument to a function expression, then that function is called as a function, not as a method, so "this" again refers to the global object, but the function closure retains its scope chain. This can be used to your advantage: function timer() { alert(this.t); var self = this; setTimeout(function(){self.timer();}, this.t); } This causes the timeout to call a function that knows the current "this" object (by the name "self"), and calls the "timer" method on it as a method. [end copy]
On 7/21/06, Thomas Fuchs <t.fuchs-moWQItti3gBl57MIdRCFDg@public.gmane.org> wrote:> > AFAIK the setTimeout makes sure that the eval() is executed in the > window-global context, > and not the local execution context of the method it happens to be in.The way Prototype.js uses setTimeout doesn''t do this as I noted in another post. There is a way to do what you suggest. I just learned about this approach. http://groups.google.com/group/comp.lang.javascript/tree/browse_frm/thread/f4cb3fae3eb9ea4c/60b52777163fe8ac?rnum=1&hl=en&_done=%2Fgroup%2Fcomp.lang.javascript%2Fbrowse_frm%2Fthread%2Ff4cb3fae3eb9ea4c%3Fhl%3Den%26#doc_89bc83a21339f05a