I'm new to Javascript, and I'm analyzing the following code. My question is: for the setTimeout() function, how is it being called? It looks to me like it's just being assigned to the variable this.timer, and that it has not yet been called. But the function is executed nonetheless. What am I missing / not understanding? Thank you so much for your help in advance!
$(document).ready(function () {
var validateUsername = $('#validateUsername');
$('#username').keyup(function () {
var t = this;
if (this.value != this.lastValue) {
if (this.timer) clearTimeout(this.timer);
validateUsername.removeClass('error').html('<img src="images/ajax-loader.gif" height="16" width="16" /> checking availability...');
this.timer = setTimeout(function () {
$.ajax({
url: 'ajax-validation.php',
data: 'action=check_username&username=' + t.value,
dataType: 'json',
type: 'post',
success: function (j) {
validateUsername.html(j.msg);
}
});
}, 200);
this.lastValue = this.value;
}
});
});
how is it being called?
The function name (setTimeout) is followed by a ( character, then some arguments, then a ) character.
The first of those arguments is a function expression that is split across multiple lines.
It looks to me like it's just being assigned to the variable this.timer
Its return value (an identifier that can be used with clearTimeout) is being assigned, not the setTimeout function itself.
Executes a code snippet or a function after specified delay.
setTimeout trigger the given function parameter(first parameter) after amount of miliseconds parameter(second parameter).
the return value is:
timeoutID is the numerical ID of the timeout, which can be used later with window.clearTimeout.
Make sure to real all the MDN page
The function is called here:
this.timer = setTimeout(function() {...});
setTimout() executes the anonymous function after the delay and meanwhile returns its numerical ID. this.timer then stores that ID, which can be later with clearTimeout.
Related
I am reading a project that I have to work and do additional work on, but I don't understand some interval trickery that has been done and not explained by the previous person. That's the code:
var intervalId;
var intervalIdtwo;
$(document).on('click', 'li.mention-individuals', function() {
clearInterval(loadTimer);
var otheridFromSearch = $(this).data('profileid');
var searchImage = $(this).find('img.search-image').attr('src');
var searchName = $(this).find('.mention-name').text();
$('.users-right-pro-pic img').attr('src', searchImage);
$('.users-right-pro-name').text(searchName);
$('.user-info').attr("data-otherid", otheridFromSearch);
xyz(useridd, otheridFromSearch, abc);
$.post('http://localhost/facebook/core/ajax/message.php', {
showmsg: otheridFromSearch,
yourid: useridForAjax
}, function(data) {
$('.msg-box').html(data);
$('.user-show').empty();
$('.top-msg-user-photo img').attr('src', searchImage);
$('.top-msg-user-name').text(searchName);
scrollItself();
})
if (!intervalId) {
intervalId = setInterval(function() {
loadMessageFromSearch(useridForAjax, otheridFromSearch);
}, 1000);
clearInterval(intervalIdtwo);
intervalIdtwo = null;
} else if (!intervalIdtwo) {
clearInterval(intervalId);
intervalId = null;
intervalIdtwo = setInterval(function() {
loadMessageFromSearch(useridForAjax, otheridFromSearch);
}, 1000);
} else {
alert('Nothing found');
}
})
function loadMessageFromSearch(useridForAjax, otheridFromSearch) {
var pastDataCount = $('.past-data-count').data('datacount'); //if no new data, the old messages will be shown
$.ajax({
type: "POST",
url: "http://localhost/facebook/core/ajax/message.php",
data: {
showmsg: otheridFromSearch,
yourid: useridForAjax
},
success: function(data) {
$('.msg-box').html(data);
}
})
$.post('http://localhost/facebook/core/ajax/message.php', {
dataCount: otheridFromSearch,
profileid: useridForAjax
}, function(data) {
if (pastDataCount == data) {
console.log('data is same');
} else {
scrollItself();
console.log('data is not same');
}
})
}
I generally get the code, but the Ifs section with the IntervalId and IntervalIdTwo - I have no clue what it does. Any tips or explanations would be greatly appreciated!
On the surface, the setInterval function is simple: it takes a function and a number n and calls the function (at most) every n milliseconds. It also returns a "handle" that allows you to cancel the repeated invocations by calling clearInterval with the handle.
For instance, here is a function that logs a string to the console:
function sayHello() {
console.log('hello!');
}
We can call it every second (1000 milliseconds) like so:
setInterval(sayHello, 1000);
(You can even try it out in your browser's dev. tools right now! It should print 'hello!' every second)
What if we want to stop printing 'hello!'? If we "hold onto" the return value, we can cancel the repeated invocations:
const handle = setInterval(sayHello, 1000);
(If you're curious, try printing handle!)
To cancel the process, call the clearInterval function with the handle:
clearInterval(handle);
A couple of notes:
In a lot of cases, it is a pain to define a separate function like sayHello, so we would instead use an "anonymous function", like:
setInterval(function() {
console.log('hello!');
}, 1000);
// or
setInterval(() => console.log('hello!'), 1000);
This underscores the fact that setInterval is a higher-order function: it takes another function as one of its arguments. This can take some getting used to, but with practice it becomes second nature.
Depending on how "busy" your browser is, the invocations may not take place at exactly the interval you specify. The delay may be longer than the number you provide, but never shorter (see 3. below for why).
if you really want to grok setInterval you will need an understanding of JavaScript's concurrency model.
So I'm doing an autocomplete search using jquery. I have to set a delay before executing the ajax function because I don't want to hammer my server with calls every time I type on a textbox. Here is my code:
function searchVendor() {
setTimeout(searchVendor2, 5000);
}
function searchVendor2() {
var search = $('#inputVendor').val();
$.ajax({
type: 'POST',
url: '/getVendors',
data: {search: search},
dataType: 'json',
success: function(s) {
$('#inputVendor').autocomplete({source: s});
}
});
}
so the function searchVendor is executed onkeyup
<input type="text" class="form-control input-sm" id="inputVendor" onkeyup="searchVendor()">
If I type 3 characters (ex. sas) then the function searchVendor2 is executed 3 times. The 5 seconds delay works but it didn't stop and overwrite the previous setTimeout.
What I want to happen is, if I type a character on the textbox it will be executed after 5 seconds, BUT! if a new character is typed before the 5 seconds, setTimeout is reset again to 5 seconds. As long as the user is typing on the textbox the setTimeout is reset to 5 seconds and it will ONLY be executed if the 5 seconds elapsed without the user typing again.
Thanks to those who can help!
First, you need to save your timeout id in a global variable, or in a variable that can be accessed later when the function is called again.
Now, whenever your function is called, first you clear that timeout if it exists. Thus you clear any pre-existing timeouts and set a new one every time the function is called.
var myTimeout;
function searchVendor() {
clearTimeout(myTimeout);
myTimeout = setTimeout(searchVendor2, 5000);
}
function searchVendor2() {
var search = $('#inputVendor').val();
$.ajax({
type: 'POST',
url: '/getVendors',
data: {search: search},
dataType: 'json',
success: function(s) {
$('#inputVendor').autocomplete({source: s});
}
});
}
The other answers involving setTimeout() are simple and will work, but this is one of the few times when I would recommend using a utility library as they can go a few steps further in a way that is noticeable to the user.
It is also important that we avoid re-inventing the wheel. And in this case, what you want is a debounce or throttle function to limit the number of times your handler gets executed within a given time span. The good libraries also accept options to tweak when exactly your handler gets run, which can affect the responsiveness of your app.
Read more about debouncing and throttling.
For your use case, I would recommend Lodash's _.throttle() with both leading and trailing options set to true. This will ensure that long entries of text will still get some intermediate results, while also getting results as fast as possible (not having to wait for a timer the first time around) and still guaranteeing that the final keystroke will trigger a new result, which not all debounce settings would do.
const handler = (evt) => {
console.log('I will talk to the server.');
};
const throttled = _.throttle(handler, 500, {
leading : true,
trailing : true
});
Then register the throttled function as the event listener.
<input type="text" class="form-control input-sm" id="inputVendor" onkeyup="throttled()">
You must clear the timeout when you want to stop it. Instead of just doing this:
var timeoutId;
function searchVendor() {
timeoutId = setTimeout(searchVendor2, 5000);
}
you should add clearTimeout(timeoutId);, like this:
var timeoutId;
function searchVendor() {
clearTimeout(timeoutId);
timeoutId = setTimeout(searchVendor2, 5000);
}
You can use minLength of autocomplete so that the API is not called as soon as the user starts typing.
Here is the reference from autocomplete
minLength: The minimum number of characters a user must type before a search is performed
$( "#inputVendor" ).autocomplete({
minLength: 3
});
If you want on every keypress, as other answers suggested, you can use clearTimeout to remove the old timeout.
var timeout;
function searchVendor() {
clearTimeout(timeout);
timeout = setTimeout(searchVendor2, 5000);
}
The setTimeout and setInterval functions can be stopped using clearTimeout or clearInterval functions, passing the unique identifier generated by the first ones. For example, here you have a small code that helps you to understand this:
var delay;
document.addEventListener("mousemove", function () {
callSetTimeout();
});
function callSetTimeout () {
if (!isNaN(delay)) { clearTimeout(delay); }
delay = setTimeout(function () {
console.log("do something");
}, 5000);
}
I change the timeout but I check with interval
var goal={
cb: cb
, timeout: (+new Date())+60000 //one minute from now
, setInterval(function(){
if((+new Date())>goal.timeout){cb();}
})
};
Now I want to increase, decrease or reset the timeout?
goal.timeout-=1000;
goal.timeout+=1000;
goal.timeout=60000;
jQuery (fragmented for simplicity)
The interval property contains an setInterval() function with in the object literal slider, the setInterval() defined in interval is invoking itself, or at-least appears to be, but why?
var slider = {
config : function(imgs, callback){
//mandatory
var images = $(imgs);
//optional
var animationInterval;
var animationTime;
callback(images);
},
target : 0,
get lastElem(){
return this.images.length-1;
},
interval : setInterval(function () {
setSlider();
}, 3000)
};
slider.config('ul.images li', setConfig);
slider.images.hide().first().show();
function setConfig(imgs){
slider.images = imgs;
}
function setSlider(dest) {
slider.target === slider.lastElem ? slider.target = 0 : slider.target++;
slider.images.hide().eq(slider.target).fadeIn(1000);
slider.triggers.removeClass('active').eq(slider.target).addClass('active');
}
JSFiddle
When you make an object literal, the values you type in are evaluated as expressions.
function square(x) {
return x * x;
}
var lookup = {
'two': square(2)
};
console.log(lookup['two']); // 4
Here, you're calling setInterval instead of square. setInterval takes a function and period and schedules that function to run repeatedly. It returns a numeric identifier of the scheduling, so that you can stop it later with clearInterval. For example, you could later do clearInterval(slider.interval); to stop setSlider from being called.
In your current code you are assigning the RESULT of setInterval() to the interval property. What I would suggest is to wrap the setInterval() call in a function, like this:
interval : function() {
setInterval(function() {
setSlider();
}, 3000);
}
Then, you should be able to call slider.interval()
Can someone please explain to me what is wrong with my code below? I am declaring a public variable and setting it to a setTimeout, and if not null, clearing the timeout before it gets set again. When I try to clear the timeout I get undefined so the timeout continues to run.
var usernameCheckTimeout = null;
$(document).ready(function(){
$("#username").on("keyup", function(e){
if($(this).val().length >= 6)
{
if(usernameCheckTimeout != null)
{
clearTimeout(usernameCheckTimeout);
}
usernameCheckTimeout = setTimeout(isUsernameAvailable($(this).val()), 1000);
}
});
});
function isUsernameAvailable(username)
{
$.ajax({
url : "/account/username-check",
method : "POST",
dataType : 'json',
data : {
'username' : username
}
}).done(function(data) {
console.log(data);
});
};
You do not need to do the null check also you need to create a closure around this, otherwise this will refer to not what you think this actually is.
var usernameCheckTimeout;
$("#username").on("keyup", function (e) {
if ($(this).val().length >= 6) {
clearTimeout(usernameCheckTimeout);
var that = this;
usernameCheckTimeout = setTimeout(function () {
isUsernameAvailable($(that).val();
}, 1000);
}
});
Some jsfiddle love like usual.
The timeout is being cleared. The problem is that you are calling your function immediately instead of passing the function to setTimeout.
setTimeout(isUsernameAvailable($(this).val()), 1000);
isUsernameAvailable($(this).val()) will be called and the result of this call will be passed to setTimeout.
You should instead pass a function which calls this function:
EDIT: As #Mark said, you also need to deal with this not being what you expect:
var value = $(this).val();
setTimeout(function(){
isUsernameAvailable(value)
}, 1000);
You have a couple of issues. The first issue, which is huge, is that you are executing isUsernameAvailable($(this).val()) immediately and passing the return value to setTimeout - you need to move this into an anonymous function so it does not execute until the anonymous function is called by the timeout:
usernameCheckTimeout = setTimeout(function () {
isUsernameAvailable($(this).val());
}, 1000);
the javascript timeout functions rely on numeric IDs to function. You should avoid testing for null or undefined or anything else, and instead test for a number:
// leave it as undefined
var usernameCheckTimeout;
...
if (typeof usernameCheckTimeout === 'number') {
clearTimeout(usernameCheckTimeout);
}
It is maybe incredibly easy but I couldn't solve what was going on.
function doSomething(a)
{
var num=10;
return setTimeout(
function(){ a(num); }, 1000);
}
The only thing that actually confuses me is the a(num) part. What actually it does?Reminder: I really am asking because I'm not familiar with the javascript syntax.
When the function doSomething() is executed it is passed the parameter a,
a is also some function that is then called when setTimeout() expires after 1 second,
then calling the function a() passing the argument called num
Example usage:
// call doSomething() passing the test() function as an argument
doSomething(test);
// takes a number as an argument and shows an alert with that value
function test(number)
{
alert(number);
}
// takes a function as an argument that will perform a 1 second timeout then execute the function called a
function doSomething(a)
{
var num=10;
return setTimeout(
function(){ a(num); }, 1000);
}
It calls the function referenced by the variable a, using the value referenced by the variable num as an argument.
setTimeout returns a timeoutID which can be used to cancel it using clearTimeout, so if you run doSomething a lot of times you will get different integer numbers which represent different timeoutID.
In your case a must be a function so you can call it using the parameter num
Example:
function doSomethingElse (justANumber) {
return justANumber + 1;
}
// Here you call your function
doSomething(doSomethingElse);
// or another special case
doSomething(function (justANumber) {return justANumber + 1;});