Complex client-side javascript problem, need help

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Derek

    Complex client-side javascript problem, need help

    Hi,

    I've built a rather large CGI that dumps a lot of data and a fairly
    complex javascript app out to the client's browser. Granted this may
    be poor style according to someone web design philosophy but that is
    the way things need to work for now here. The problem I'm having is
    that it appears that the browsers (IE, mozilla and netscape) are
    sometimes getting confused about wether the javascript code is
    running. By this I mean when I click a button that runs some filtering
    functions on the data that was sent over by the CGI there are times
    when it can take 10-15 seconds before the function finises executing.
    But the filtering function always exits properly and when it does so
    CPU utilization goes from 100% back to a normal 2-4% on my machine. At
    this point I can continue to interact with the javascript app in my
    browser, but sometimes the progress indicator in the status bar will
    still keep moving as if processing is continuing in the background.
    Also on occasion I've seen an error message pop-up (sometime during
    but mostly after the filtering function) which says that the
    javascript is making the browser run slowly do you want to continue.
    After seeing this message the function has usually finished its work
    so you click on yes to continue and everything is fine.

    So, is there some way I can help the browser not loose track of the
    fact that the javascript function has already returned?

    And also is there a way to disable/prevent the browsers from
    displaying the message about the javascript code causing the browser
    to run slowly?

    Finally what is the best way to give the users visible feedback that
    the filtering function is working and that things aren't locked up?
    The cursor doesn't change to the hourglass when the function is
    running. And when I tried to output to another frame some progress
    messages none of that data appeared in the frame until after the
    filtering function had returned.

    Thanks in advance for any help.

    Derek
  • Yep

    #2
    Re: Complex client-side javascript problem, need help

    dealy663@hotmai l.com (Derek) wrote in message news:<60fbcb9d. 0308191315.6f33 baa5@posting.go ogle.com>...
    [color=blue]
    > Finally what is the best way to give the users visible feedback that
    > the filtering function is working and that things aren't locked up?
    > The cursor doesn't change to the hourglass when the function is
    > running. And when I tried to output to another frame some progress
    > messages none of that data appeared in the frame until after the
    > filtering function had returned.[/color]

    You could (1) split the main job in little jobs (easy if you have some
    kind of a loop in your main job) and (2) chain the job parts calls
    with timeouts, in order for the UI to get updated and the browser not
    to get terrified at how fast your script is eating memory :-) To put
    it another way, you'd give the browser some time to breathe while
    working. The following quick demo should demonstrate the technique,
    you'll have to make the split and find a more elegant way to inform
    the user, though.


    <script type="text/javascript">
    //emulate the job part
    function JobPart(){ /1(.+)+1/.test("011000") ; }

    // emulate the job chain
    var A_Jobs=[]
    for(var ii=0; ii<100; ii++)
    A_Jobs[ii]=JobPart;

    // job controller
    var Job = function() {
    var ii=0, d=document;
    var UserInform = {
    start : function() { c("wait"); window.status=" 0%"; },
    update : function(state) { window.status=s tate+"%"; },
    stop : function() { c("default"); window.status=" "; }
    };
    var c=function(a){d ocument.body.st yle.cursor=a;};
    return function (){
    UserInform.star t();
    A_Jobs[ii++]();
    UserInform.upda te(Math.floor(i i*100/A_Jobs.length)) ;
    if (ii<A_Jobs.leng th) setTimeout(argu ments.callee, 1);
    else {
    ii=0;
    UserInform.stop ();
    }
    }
    }();
    </script>

    <input type="button" value="Lauch job" onclick="Job()" >


    HTH
    Yep.

    Comment

    • mehdi amini

      #3
      Re: Complex client-side javascript problem, need help

      "Yep" wrote:
      ...........[color=blue]
      > <script type="text/javascript">
      > //emulate the job part
      > function JobPart(){ /1(.+)+1/.test("011000") ; }
      >
      > // emulate the job chain
      > var A_Jobs=[]
      > for(var ii=0; ii<100; ii++)
      > A_Jobs[ii]=JobPart;
      >
      > // job controller
      > var Job = function() {
      > var ii=0, d=document;
      > var UserInform = {
      > start : function() { c("wait"); window.status=" 0%"; },
      > update : function(state) { window.status=s tate+"%"; },
      > stop : function() { c("default"); window.status=" "; }
      > };
      > var c=function(a){d ocument.body.st yle.cursor=a;};
      > return function (){
      > UserInform.star t();
      > A_Jobs[ii++]();
      > UserInform.upda te(Math.floor(i i*100/A_Jobs.length)) ;
      > if (ii<A_Jobs.leng th) setTimeout(argu ments.callee, 1);
      > else {
      > ii=0;
      > UserInform.stop ();
      > }
      > }
      > }();
      > </script>
      >
      > <input type="button" value="Lauch job" onclick="Job()" >
      >
      >[/color]
      ............... ....

      It looks great but would you (or others) mind to explain this peace of code
      a bit more?


      Just curious...

      Thanks
      m


      Comment

      • Yep

        #4
        Re: Complex client-side javascript problem, need help

        "mehdi amini" <m@grauland.d e> wrote in message news:<bi4ure$40 d$00$1@news.t-online.com>...
        [color=blue]
        > It looks great but would you (or others) mind to explain this peace of code
        > a bit more?[/color]

        Sure; the goal was to expose the setTimeout method to the OP, and the
        interest of using it recursively to form a chain of timed calls; if
        you want to know more about this, check the archives at clj for
        "setTimeout " and "setInterva l", especially Richard Cornford
        'TimedQue', for instance at

        <URL: http://groups.google.c om/groups?hl=en&lr =&ie=UTF-8&oe=UTF-8&selm=bdqk4h%2 4d3v%241%248302 bc10%40news.dem on.co.uk&rnum=3 >

        As for the code, explanations follow.
        [color=blue][color=green]
        > > //emulate the job part
        > > function JobPart(){ /1(.+)+1/.test("011000") ; }[/color][/color]

        This part is used to emulate a job part; in reality you'd have a big
        loop, such as
        for(var ii=0; ii<bigNumber; ii++) {
        doStuff(ii);
        }
        The idea is to execute 10 or more little loops instead of the big one,
        so something like
        function doStuffPart(sta rt, end){
        for(var ii=start; ii<end; ii++){
        doStuff(ii);
        }
        }
        and call doStuffPart many times, with a timeout between each one in
        order to give the browser the time to update the UI. The feasibility
        depends on the stuff to be done :-)

        The regexp used in the JobPart function is a killer for a regex
        NFA-based engine, as javascript's. Adding more trailing zeros to the
        string being tested can slow down the script, and I've found it a
        quick way to emulate a consequent jobPart in a short line.
        [color=blue][color=green]
        > > // emulate the job chain
        > > var A_Jobs=[]
        > > for(var ii=0; ii<100; ii++)
        > > A_Jobs[ii]=JobPart;[/color][/color]

        An array of jobs; since there is only one function, this would be
        neater to just call the function and throw the array away, but I had
        before experimented with different jobPart funcs, and decided to leave
        the array construction so that different JobParts could be called
        without problem if needed.

        The following part is more complicated, I've adopted a closure
        approach, since I considered the two previous parts to be "only"
        simple emulation and the following one to be the real issue (so
        conception mattered) - moreover closures have been discussed a lot
        recently and as a result I've come to use them quite often (thanks
        Richard) :-)

        To know more about closures, check the archives, especially the
        following thread "Closures, what are they good for":

        <URL: http://groups.google.c om/groups?hl=en&lr =&ie=UTF-8&oe=UTF-8&threadm=b8dsh d%24d46%241%248 302bc10%40news. demon.co.uk&rnu m=1&prev=/groups%3Fhl%3De n%26lr%3D%26ie% 3DUTF-8%26oe%3DUTF-8%26q%3Dclosure s%26btnG%3DGoog le%2BSearch%26m eta%3Dgroup%253 Dcomp.lang.java script>
        [color=blue][color=green]
        > > // job controller
        > > var Job = function() {
        > > var ii=0, d=document;
        > > var UserInform = {
        > > start : function() { c("wait"); window.status=" 0%"; },
        > > update : function(state) { window.status=s tate+"%"; },
        > > stop : function() { c("default"); window.status=" "; }
        > > };
        > > var c=function(a){d ocument.body.st yle.cursor=a;};
        > > return function (){
        > > UserInform.star t();
        > > A_Jobs[ii++]();
        > > UserInform.upda te(Math.floor(i i*100/A_Jobs.length)) ;
        > > if (ii<A_Jobs.leng th) setTimeout(argu ments.callee, 1);
        > > else {
        > > ii=0;
        > > UserInform.stop ();
        > > }
        > > }
        > > }();
        > > </script>[/color][/color]

        The Job variable is assigned the _result_ of an anonymous function,
        executed at the same time it is declared. This result appears to be a
        function, but since this function is nested inside the executed one,
        the local variables of the outer function are still available to the
        inner function (the one that does the work), but completely hidden to
        anything else - they are perfect private static members.

        These members include "ii", used as an index for the JobParts array,
        "d" as a pointer to document (keeping reference not only makes the
        code faster and neater, but also easier to post in a NG, where you
        have to limit code to 72 chars to avoid line breaks!).

        UserInform is a simple object used as an interface to the UI, with
        three methods (start, update and stop). The controller just calls the
        appropriate methods to update the UI, if you want to remove the
        terrible window.status with DHTML you just have to replace the content
        of the methods.

        "c" is a simple helper to update the cursor, as wanted by the OP.

        The inner anonymous function (the one returned and being assigned the
        the "Job" variable) does the whole job: lauching the job parts one
        after the other, using private static vars to keep track of where it
        is (it needs to keep the information outside of its own scope,
        otherwise the info will be cleared as soon as the function has
        executed). The setTimeout part is the real thing to understand, with
        the function calling itself recursively (note how the scope chain
        remains unaltered). The "1" timeout value will result in the function
        being called as soon as possible (around 10msec in Win2k and 50ms on
        Win98) - and this is enough to give the browser the opportunity make
        the relevant UI updates and keep the script as fast as possible.

        Of course adding such a "monitoring " feature will slow down the whole
        script (be it table sorting, high calculations etc), but the benefit
        for the user is invaluable in the end.


        HTH
        Yep.

        Comment

        • Richard Cornford

          #5
          Re: Complex client-side javascript problem, need help

          "Yep" <y-e.perio@em-lyon.com> wrote in message
          news:d2d855ea.0 308221200.b01ae 6c@posting.goog le.com...
          <snip>[color=blue]
          >... - moreover closures have been discussed a lot
          >recently and as a result I've come to use them quite
          >often (thanks Richard) :-)[/color]
          <snip>

          You are welcome! But, do you remember a thread where we were discussing
          my use of an expando to mask a global public static method so that
          subsequent event handling calls would scope resolve to the expando. In
          relation to some aspect of that script you asked me if I thought using
          closures instead had any problems. At the time I didn't know, I had not
          used, and did not sufficiently understand closures, but I thought I had
          better find out. (Actually I though; If Yep is interested in closures
          they must be interesting so I will find out how and why. :-)

          So, thank you, for setting me of in pursuit of closures and into one of
          the most interesting areas of JavaScript (and easily my favourite now).

          Incidentally, I recently re-wrote a closure-based nested object DHTML
          script into a standard public member/prototype script that did the same
          processor intensive animation operations so that I could directly
          compare accessing private instance members (as outer function local
          variables) with accessing the same values as public members via the -
          this - keyword. It seems (on all the browsers that I tested) that the
          interpreter resolves outer function local variables faster than it can
          access public members using the - this - keyword. So there is a manifest
          advantage in using closures in performance critical scripts (Traded off
          against increased memory use and slightly greater time to initialise the
          objects due to the need to create more function objects).

          Next is regular expressions (I wonder why ;-). I don't use them much, I
          don't understand them sufficiently, but give me 6 months ...

          Richard.


          Comment

          Working...