yaru yaru - 3 months ago 6
Javascript Question

How to run code from javascript widget after 10 secs of page load?

I have created a javascript widget that displays popups and anyone can embed it on their websites by pasting a few lines of code before closing

</body>
tag.

While configuring it a user can specify that he wants a popup to be displayed after 10 secs of page load. But since my script depends on
jQuery
and before executing its main code it must load it first - sometimes script executes its
main()
function much later than in 10 secs...

So currently the steps are:


  1. Web page is loaded (I do not know how much time it will take)

  2. My script is loaded (I do not know how much time it will take)

  3. My script loads jQuery if necessary (I do not know how much time it will take)

  4. Only when jQuery is loaded it starts counting 10 secs and then runs
    displayPopup
    function



As you can see it's unsafe to run
displayPopup
function in 10 secs after
$(document).ready
event because it may not load jQuery or itself yet. And it's okay - it's a technical restriction I can not do anything about (right?).

I just need a way to know how much time has passed since
$(document).ready
event. And then I will check this number of seconds inside my
main()
function and decide if I need to display popup immediately (if page was loaded > 10 secs ago) or wait a few seconds.

Script install code:

<script>
(function() {
var scriptTag = document.createElement("script");
scriptTag.type = "text/javascript";
scriptTag.async = true;
scriptTag.src = "https://www.server.com/script.js";

var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(scriptTag, s);
})();
</script>


Loading jQuery part of script.js

if (window.jQuery === undefined || window.jQuery.fn.jquery !== '1.12.4') {
var script_tag = document.createElement('script');
script_tag.setAttribute("type","text/javascript");
script_tag.setAttribute("src",
"//ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"
);

if (script_tag.readyState) {
script_tag.onreadystatechange = function () {
if (this.readyState == 'complete' || this.readyState == 'loaded') {
scriptLoadHandler();
}
};
}
else {
script_tag.onload = scriptLoadHandler;
}

(document.getElementsByTagName("head")[0] ||
document.documentElement).appendChild(script_tag);
}
else {
jQuery = window.jQuery;
main();
}

function scriptLoadHandler() {
jQuery = window.jQuery.noConflict(true);
main();
}


Main function:

function main() {
setTimeout(function() {
displayPopup();
}, settings['numberOfSeconds'] * 1000);
}

Answer

You don't have to mess with timetous or intervals. Its pretty simple actually from my point of view, considering I got everything right.

Once you got document.ready grab the current timestamp. Let it be documentReadyAt.

Once jquery was loaded grab the current timestamp again. Let it be jqReadyAt.

Compare the jqReadyAt against documentReadyAt and find the difference. If jQuery already exists the difference will be insignificant. A matter of couple milliseconds. If jquery had to be loaded will be more than 100ms to few seconds.

Start counting whatever you like.

var documentReadyAt, jqReadyAt;
document.onreadystatechange = function () {
    if (document.readyState === "complete" && documentReadyAt === undefined) {
        documentReadyAt = new Date();
        loadJQ(); // Loading jQuery part of script.js. 
    }
}

//function loadJQ(){ ...whatever you wrote to load jquery }

//For the sake of handling same logic in one place will assign a variable to jqReadyAt here. Could also be done at `main()` without noticeable cost.
function scriptLoadHandler() {
  jqReadyAt = new Date();
  jQuery = window.jQuery.noConflict(true);
  main();
}

//Main will change to that one.
function main() {
  var millisPassedSinceDocLoaded = jqReadyAt.getTime() - documentReadyAt.getTime();
  setTimeout(function() {
    displayPopup();
  }, (settings['numberOfSeconds'] * 1000) - millisPassedSinceDocLoaded );
}