31

I am trying to create a syntax highlighter script. I tried using my script on a code with 10 thousand lines, and all I see is a blank page while it is loading. Everything will just show up after the script has finished its task. By the way, I called my script inside the ready function of jQuery.

$(myFunction);

The script should execute after the page is fully rendered, and the user can actually navigate through the page even if the script is not yet finished. The javascript will run in the background as it highlights the code one by one while not interfering with the responsiveness of the page. Thanks in advance.

EDIT:

To make this clearer, I would like to execute the code after everything is "rendered," not "loaded". Everything should already be visible in the screen and the user can actually see the code come to life as it is being highlighted. Thanks.

Robert Bradley
  • 548
  • 2
  • 21
Randal Cunanan
  • 2,449
  • 6
  • 29
  • 38
  • That code snippet is for when the DOM is ready to be manipulated, not when every resource has loaded. Unfortunately, I don't know of any clear and non-buggy way to check that every element has loaded. – nickjyc Dec 23 '11 at 02:44
  • possible duplicate of [How do you execute a Javascript function when the page has fully rendered?](http://stackoverflow.com/questions/939538/how-do-you-execute-a-javascript-function-when-the-page-has-fully-rendered) – JosephStyons Dec 23 '11 at 16:51
  • You should use async in script tag, webworkers, and onload event for creation of webworkers. – Muhammad Umer Mar 06 '14 at 04:25
  • Webworkers are cool and all, but they're not fully supported. I would just put an image (even a blank transparent one) at the bottom of your DOM, it should be the last thing loaded by the browser, so the "onload" for that image can call your "highlight" function. – Mike Oct 02 '14 at 14:54

5 Answers5

33

Do you mean after all the images have been loaded?

I think window.onload is what you're looking for

window.onload = function() {
    //dom not only ready, but everything is loaded
};

EDIT

Per Chris's comment, here's the jQuery way:

$(window).load(function() {
    //dom not only ready, but everything is loaded
});
Adam Rackis
  • 82,527
  • 56
  • 270
  • 393
  • 1
    The jQuery way of doing this would be $(window).load(function(){...}); – ChrisM Dec 23 '11 at 02:51
  • 1
    The solution did not work. The page is still blank while javascript is loading. Any other solution? I have edited my post to emphasize what I want to happen. Thanks. – Randal Cunanan Dec 23 '11 at 03:21
  • 3
    Ok, the term I am looking for is non-blocking javascript. The javascript should not block the rendering and responsiveness of the browser. The above solution is for executing codes after the page has loaded, but still blocks the rendering of the page. Any ideas? Thanks. – Randal Cunanan Dec 23 '11 at 03:32
  • @RueLeonheart - I don't think that's possible, not 100% certain though – Adam Rackis Dec 23 '11 at 03:36
  • 3
    `$(window).load(function() { ... }` has been deprecated. You have to use `$(window).on('load', function(){ ...});`. [More info here](https://stackoverflow.com/a/40252711/3543339). – Jwags Jan 24 '20 at 22:56
12

in case you didn't try this yet, 9 years later …

$(document).ready(function () {
    window.setTimeout('ctlEmployeeEdit.document_load()', 50);
    });

I guess if you set your time out to 9 years of milliseconds, the page will probably have rendered, but that's just my hypothesis!

Todd Harvey
  • 309
  • 3
  • 4
  • 1
    The jQuery ready event happens after the page is fully loaded. So adding a delay via setTimeout serves no purpose since page has already rendered. And in fact, the solution doesn't even require jQuery at all. If the highlight script is simply added at the bottom of the page it gets run after the page is rendered. See related SO post: https://stackoverflow.com/a/6026730/943435 – Yogi Oct 20 '21 at 10:51
  • @Yogi That wasn't the case for me. `setTimeout` even with no delay caused the script to execute after the first content is rendered, while without it, it was done before. I notice because I'm executing a code highlight function with a processing time of 500ms. – Nearoo May 08 '22 at 16:25
9

Problem with window.onload approaches

Even if you use the $(window).load approach, your highlighter stuff could get run prior to something from $(document).ready completing, since there may be lots of asynchronous callback functions all over the place.

My approach

I use a combination of waiting for document.readyState == 'complete and setTimeout. The idea is that I want to wait until the page is fully rendered (hence the 'complete') and then further ensure that the $(document).ready JQuery wrapper content has completed (hence the setTimeout).

Here's how I would solve your problem, assuming that 200 milliseconds is ample time for everything inside $(document).ready(function(){ /*...*/ }); to complete.

function highlighterAction() {
    // actually do the highlighting stuff here
}

function highlighter() {
    /*
      The short pause allows any required callback functions
      to execute before actually highlighting, and allows
      the JQuery $(document).ready wrapper to finish.
     */
    setTimeout(function() {
        highlighterAction();
    }, 200);
}

/*
  Only trigger the highlighter after document fully loaded.  This is
  necessary for cases where page load takes a significant length
  of time to fully load.
*/
if (document.readyState == 'complete') {
    highlighter();
} else {
    document.onreadystatechange = function () {
        if (document.readyState === "complete") {
            highlighter();
        }
    }
}
synaptik
  • 8,971
  • 16
  • 71
  • 98
0

I know the original poster will have long since moved on from this 10yr-old question. But I hope this answer may help someone.

First off, good async programming and the use of window.onload are probably a big part of the solution. Individual implementations will vary.

Another problem that we're trying to overcome here, I think, is that too much work is being done in the main thread on the client. Other than writing more efficient code, there's no trick I can think of to get around that problem. The only solution is to not do that work on the main thread. One option is to do more work on the server.

Another option is to use a web worker to put that work in a background thread. You can't directly update the DOM from the worker thread, but you can still do most of the prep work.

If you've never used web workers before, don't be intimidated; they're pretty quick to implement, assuming you know JavaScript. All you really need to get started are new Worker() to start a background thread, postMessage() to send data from the main thread to the worker thread (or vice versa) and the onmessage event handler for receiving the data (in either direction).

It's like a pure function that runs without blocking the DOM, and calls you back with data when it's done.

Here's an example implementation in which there's an initial page render of black text. Meanwhile, the web worker decides blue is better, thinking about it for 2 long, hard seconds, then reporting the result back to the main thread. The main thread then updates the DOM in response.

<body>
  <div id="cool-div"></div>
  <script>
    let myData = [
      "This is my sample data that I want to do a bunch of work to, such as parsing it and returning new html to render.",
    ];
    document.getElementById(
      "cool-div"
    ).innerHTML = `<p style="color:black">${myData}</p>`;
    const myWorker = new Worker("worker.js");
    myWorker.onmessage = (event) =>
      (document.getElementById("cool-div").innerHTML = event.data);
    myWorker.postMessage(myData);
  </script>
</body>

Then in worker.js:

onmessage = (e) => {
  const newData = `<p style="color:blue">${e.data}</div>`;
  //pretend to do hard work, then pass the result back to main thread
  setTimeout(() => postMessage(newData), 2000);
};
0

Not sure exactly how much data is being brought in...but what if on document ready you ran a jquery ajax call and used the completed method to run your highlighter function? If there is a lot of data it will be a slower page load.

Anyways would like similar to this

$.ajax({
            type: "POST",
            url: "Where data is actually stored",
            data: { ChannelTypeID: ChannelTypeID },
            datatype: "html",
            beforeSend: function () {

            },
            success: function (myHTML) {
                $('body').html(myHTML);
            },
            error: function () {
                alert("Ajax request was unsuccessful");
            },
            complete: function () {
                highlighterFunction();
            }
        });

The complete method specifies a function to be run when an AJAX request completes. Hopefully the success will fire early enough to push the data and allow your highlight to work properly

afreeland
  • 3,889
  • 3
  • 31
  • 42