I have a question regarding the order of execution of JavaScript (listener) methods. While I appreciate the below code is probably not best practise, is there any way to guarantee the order the below functions will fire when btn1 is changed?
$(function() {
$('#btn1').change(function(){
doStuff();
});
});
$(function() {
$(#btn1, btn2).change(function(){
doMoreStuff();
});
});
E.g. is it possible to assert that based on the order the JS code "appears in" (i.e listed in the actual js / html file), that (when #btn1 changes):
1. that doStuff() will execute first
2. that doStuff() will complete fully before doMoreStuff() is invoked – assuming all doStuff is doing is updating the DOM
I have a real example, where doStuff updates the DOM and doMoreStuff invokes an Ajax endpoint, using the updated DOM values - and want to be sure doStuff will always be invoked first (again based on the flaky design that it is "listed" first).
Thanks,
Damien
As far as I'm aware, jQuery ensures event handlers fire in the order in which they were created (first in, first out). Currently I can't find any documentation on this, but I'm sure I have read that somewhere in the past.
As long as your first change function isn't asynchronous, it should be the case that the first function will finish execution before the second starts. We can test this by adding a loop within our first change function:
$(function() {
$('#btn1').change(function(){
console.log("First change event triggered at " + +(new Date()));
for (var i = 0; i < 100000000; i++)
continue;
console.log("First change event finished at " + +(new Date()));
});
});
$(function() {
$('#btn1, #btn2').change(function(){
console.log("Second change event triggered at " + +(new Date()));
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<select id="btn1"><option>1</option><option>2</option></select>
<select id="btn2"><option>1</option><option>2</option></select>
As you can see, the first finishes before the second starts.
Related
In the book, author uses "setTimeout" to reset the form in HTML page.But I didn't find this usage in the JS document.So, why function"setTimeout()" can reset the form?
//reset
$("#reset").click(function(){
setTimeout(function() {
countChecked();//initial
$("select").change();//initial
},0);
});
function countChecked() {
var n = $("input:checked").length;
$("div").eq(0).html("<strong>"+n+" elements are selected!</strong>");
}
$("select").change(function () {
var str = "";
$("select :selected").each(function () {
str += $(this).text() + ",";
});
$("div").eq(1).html("<strong>you have selected:"+str+"</strong>");
}).trigger('change');
So, why function"setTimeout()" can reset the form?
It doesn't, it just waits to run the code within it until after the event trigged by the button click has been processed.
You haven't shown the HTML, but I'm guessing that the id="reset" button is also type="reset", which does reset the form (standard HTML functionality, no scripting required). So by waiting to call countChecked until after the reset, the code shows the state once the reset is complete.
The setTimeout() method calls a function or evaluates an expression after a specified number of milliseconds.
I see the time is set to 0 so it does not count.
Window setTimeout() Method: https://www.w3schools.com/jsref/met_win_settimeout.asp
setTimeout(function,0) or setTimeout(function), the zero is optional, both place the code to be executed at the end of the current code being executed, and after any updates the browser may have pending.
This was useful before ES6 to deblock the browser for scripts that took a long time to finish. Just use setTimeout for each iteration of the loop without a delay.
For example
setTimeout(function() { console.log(2) }); // will log 2 after this script finishs
console.log(1)
Will place into the console log 1 then 2, not 2 then 1.
I don't see the point of doing
countChecked();//initial
$("select").change();//initial
after the code which is shown, has finished?
I need to execute code from 3 different places on my website when an event gets triggered. I've added 3x listeners but for some reason only the first listener gets called.
Here's the code I'm testing at the moment: JSFiddle
window.addEventListener('tompina_event', function (e) {
document.write("triggered 1");
});
window.addEventListener('tompina_event', function (e) {
document.write("triggered 2");
});
window.addEventListener('tompina_event', function (e) {
document.write("triggered 3");
});
var evt = new CustomEvent('tompina_event');
window.dispatchEvent(evt);
Result:
triggered 1
This is the result I was hoping for:
triggered 1triggered 2triggered 3
It works, but the document.write destroys the original page and thus the execution of other code.
Please rewrite so the result is set in an other way like alert("triggered 1") or console.log("triggered 1").
The problem is with document.write(). Each call is overriding the strings from the previous call, and it appears that only one is firing. Change to console.log(), or document.body.innerHTML += "" and you will see them all firing.
The write() method is mostly used for testing: If it is used after an HTML document is fully loaded, it will delete all existing HTML.
Just wondering if the amount of document.ready calls affects page load speed.
Is there a way in Gulp / Grunt to uglify / minify JS by removing seperate document ready functions?
Just check it!
I don't see significant difference in Chrome.
As I know, it was critical for IE8, but didn't check this fact.
IE11 shows 2 seconds on the first snippet, when the others take 200 ms only.
Also, seems like jQuery already aggregates load events.
Don't forget
When you are running same code in one tab, browser remembers something and runs it faster.
Reload the page is not enought. Open a new tab instead.
After opening a new tab, run snippets in different order.
If the snippet is ran first on the tab, it will get additional slowdown, comparing the other three.
for (var q=0; q<1000; ++q) {
document.addEventListener('DOMContentLoaded', (function (i) {
console.log(i);
}).bind(null, q));
}
document.addEventListener('DOMContentLoaded', function () {
document.querySelector('output').textContent = performance.now().toFixed(3);
});
<output></output>
document.addEventListener('DOMContentLoaded', function () {
for (var q=0; q<1000; ++q) {
(function (i) {
console.log(i)
}).bind(null, q)();
document.querySelector('output').textContent = performance.now().toFixed(3);
}
});
<output></output>
for (var q=0; q<1000; ++q) {
$((function (i) {
console.log(i);
}).bind(null, q));
}
$(function () {
document.querySelector('output').textContent = performance.now().toFixed(3);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<output></output>
$(function () {
for (var q=0; q<1000; ++q) {
(function (i) {
console.log(i)
}).bind(null, q)();
document.querySelector('output').textContent = performance.now().toFixed(3);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<output></output>
Maybe it's just me as a JavaScript avoider, but none of the scripts have document.ready inside. If you JS guys talk about document.ready, that's a synonym for addEventListener('DOMContentLoaded')?
There are two events: DOMContentLoaded and load (window.onload). First of them occures when the body pasring is complete, but some assets are loading still. The second - when the page is completely loaded. First one is nice for running scripts with dom manipulations, but browsers not always had support of it.
So jQuery uses the first of these two events and classic form of subscription was
$(document).ready(function () {
// ...
});
but after some versions if was simplified to passing function directly into jQuery:
$(function () {
// ...
});
So in vanilla examples I'm using the first of 2 events, and in jQuery examples I'm using the short form of subscription on it. As browsers without support of this event are very old it's correct to assume that jQuery always uses DOMContentLoaded (probably the load way is removed in version 2 - didn't check it, but see no reasons to keep it there).
Many document ready calls shouldn't affect much the application performance. The best solution may be having only one and init there all you need. But it depends on your application structure and you should be more confortable having more than one. Anyway, I don't think there is any Gulp task that wraps different ready functions in one, because it will touch the application logic.
You can have multiple ones, but it's not always the neatest thing to do. Try not to overuse them, as it will seriously affect readability. Other than that , it's perfectly legal.
It's also worth noting that a function defined within one $(document).ready block cannot be called from another $(document).ready block.
$(document).ready(function() {
alert('hello1');
function saySomething() {
alert('something');
}
saySomething();
});
$(document).ready(function() {
alert('hello2');
saySomething();
});
output was
hello1
something
hello2
Check this post and this one
Yes, you can use multiple document ready handler, there is no special advantage even though you can use jQuery code in several place. You can’t use the variable inside one in another since those are in different scope.
Actually jQuery event handler pushing function for execution in
queue of a particular event. When event is fired all functions
executes one by one from particular events row/stack/queue based on
return value of parent sequential function.
BUT
There is one thing to note that each $(document).ready() function call
must return. If an exception is thrown in one, subsequent calls will
never be run.
$(document).ready(function() {
document.write('<h3>In First ready function</h3>');
var foo = function() {
console.log('inside foo');
}
document.write("foo:" +(typeof foo)+"<br>");
document.write("bar:" +(typeof bar)+"<br>");
});
$(document).ready(function() {
document.write('<h3>In Second ready function</h3>');
var bar=function bar() {
console.log('inside bar');
}
document.write("foo:" +(typeof foo)+"<br>");
document.write("bar:" +(typeof bar)+"<br>");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Actually jQuery $(document).ready() method is attach function with DOMContentLoaded event using addEventListener method.
Yes you can have multiple instance of it on a single page. There is no particular advantage. All will get executed on first called first run basis.
I am currently working on a book with page turn effect in jQuery (no plugin). The page turn effect works fine so far, as long as you click through the pages one by one. But now I want to include a dropdown selection (i.e. a select element) so the user can directly jump to the selected content. I tried to make this work with loops and with the .each() method, so that the turnRightPage/ turnLeftPage function is called repeatedly, until the page with the selected content is shown. But after quite a bit of trial and error and a lot of research, I think loops iterate too fast for my turnRightPage /turnLeftPage()-function (which are the transform functions that turn the respective page), in that the loop is done, before the function has completed. I think, what I need to do, is find a way to pause the loop until the function has finished executing and then resume with the next iteration. I think the most promising approach would be using a function with an iteration counter, like it was suggested here:
Javascript: wait for function in loop to finish executing before next iteration (Thanks to jfriend00 at this point) I have also read
Invoking a jQuery function after .each() has completed and
wait for each jQuery
among others, where similar solutions were suggested.
Below is how I tried to implement jfriend00's callback. I added a return statement to break out of that "callback loop", once the number of page turns is completed.
//determine whether to flip pages forward or back - first forward
if(currentPagePos < foundPagePos){ // => turn right page
//determine how many times need to turn page
if (pageDifference > 1 && pageDifference % 2 !=0) {
var numPageTurns = (pageDifference-1)/2;
pageForward (numPageTurns);
} //else if ... rest omitted for brevity
}
function pageForward (numPageTurns){
var i = 0;
function next(){
i++;
if (i <= numPageTurns){
turnRightPage ();
} else {
return;
}
}
next();
};
The full code can be seen here: http://jsfiddle.net/snshjyxr/1/
It DOES turn the page, but only once! What am I missing?
I am still very new to javascript / jQuery so my apologies, if the problem seems all too obvious. Any pointers appreciated. Thx!
The thing is all the page turns are fired, but all at once. You have to wait until each transition is finished to start the next one.
Use a callback function in your turnRightPage and turnLeftPage functions. Example for turnRightPage :
function turnRightPage(callback) {
[...]
//change class AFTER transition (frm. treehouse-site)
$page.on('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', function () {
//need to double-set z-index or else secondtime turning page open setting z-index does not work (tried in Chrome 38.0.2125.111 m)
$page.css("z-index", turnedZindex + 1);
$(".turned").removeClass("turned");
$page.addClass("turned");
if(typeof callback == "function") {
callback();
}
});
};
And in your pageForward function, use turnRightPage recursively:
function pageForward(numPageTurns) {
console.log("number of FORWARD page turns: " + numPageTurns);
if(numPageTurns > 0) {
turnRightPage(function(){
pageForward(numPageTurns - 1);
});
}
};
Here is your updated jsfiddle. As you can see, there's a remaining bug when you make several page changes which is caused by the fact that you're adding listeners on the transition end every time a page is turned, and never removing them. So they're all executing every time.
EDIT: jsfiddle updated again without the annoying last bug. As you can see, all it took was to unbind the event listener as soon as it's fired.
I need to be sure that a certain script within a page is executed as last.
I thought of using JQuery
$(document).ready( ... )
but if there are more functions of this type, which is actually executed last?
There are many ways to delay the execution of a script.
There is no way to programatically detect all of them.
For a reliable solution you would have to reverse engine the code of each page you care about, figure out what it is doing (and when) and write your delay script specifically for that page. (For a value of "reliable" equal to "until they change the page").
$(document).ready( ... )
is not executed last. The last function executed ( so, after document ready ) is the one(s) from <body onload>.
Example : <body onload="myJSfunction();">
Here, the javascript myJSfunction is executed at the end, after $(document).ready( ... ).
This depends on the order in which you have registered them.
E.g:
$(document).ready( function() { alert("first"); });
$(document).ready( function() { alert("second"); });
$(document).ready( function() { alert("third"); });
would alert "first" then "second" then "third"
So adding a <script> to the bottom of your page with an $(document).ready( yourfunction ); would suffice.
Theoretically you can do something like this:
// Form array of functions which sould be called with according order
$.readyArray = [function () { ... }, function () { ... }, function () { ... }, ...];
// just execute them in this order when onready event
$(document).ready(function() {
for (var i = 0; i < $.readyArray.length; i++) {
//apply, calls function in current context and pass arguments object
$.readyArray[i].apply(this,[arguments]);
}
});
If refactoring (as Quentin suggested) is not an option (e.g. you are updating a just part of a framework or a product), you can use four approaches, which should give you a good chance achieving what you need. See the following snippets with jQuery:
(1) Wait until 'document' is ready
By document is meant the visible DOM. The script will fire when all it should be rendered really rendered is.
$(document).ready(function() {
console.log('Document is ready.');
});
(2) Wait until top-level JS (Root) 'window' object is ready
The full root object can (will) be ready some time after the DOM is ready.
$(window).ready(function() {
console.log('Window is ready.');
});
(3) Wait until 'window' is fully loaded using .bind
This fires immediately after 'window' is ready, so your script can act on objects (elements) rendered during $(window).ready() above.
$(window).bind("load", function() {
console.log('Window bind is ready.');
});
(4) Wait until Ajax calls are completed
This is as far as you can go - the script will fire when 'window' is ready, loaded, all the code run and all the Ajax actions are completed. Unfortunately, since one Ajax can call another one, it can fire several times during the page load.
$(window).ajaxComplete(function() {
console.log('Window bind is ready, Ajax finished.');
}
In simple Javascript solution, you could call the javascript function at end of your HTML document inside the script tag. This works well when you are not using jQuery.
In case of jQuery you could use load method.The load event is sent to an element when it and all sub-elements have been completely loaded.
For more info look at
http://api.jquery.com/load-event/
Try this,
$(window).bind("load", function() {
//code here
});