How setTimeout works? - javascript

I have a concern with setTimeout function in javascript. when we call setTimeout function without return anything, it is okay for me. like
setTimeout(function() {
console.log("ok function called")
},2000);
here in the above example it just simply call that function after 2000ms,
And if I write this like
setTimeout(function(params) {
console.log("passed value is"+params)
},2000,55);
now it will call this function with 55 as an argument, right?
But problem is that when I call to write this like
setTimeout(function(params) {
console.log("passed value is"+params)
}(55),2000);
here function is calling with 55 as params but it is now waiting for 2000ms
And when I wrote like
setTimeout(function(params) {
console.log("passed value is "+params);
return function(){
console.log(params)
};
}(55),2000);
in this only return function is calling with 2000ms delay, the line console.log("passed value is "+params); is executing instantly
please help me get out of this problem.

One is a function. Another is a function call.
First, let's forget javascript for now. If you know any other programming language, what do you expect the two pieces of code below to do?
function a () { return 1 }
x = a;
y = a();
What do you expect x to be? 1 or a pointer to function a?
What do you expect y to be? 1 or a pointer to function a?
A function is not a function call. When you call a function it returns a value.
Now let's switch back to javascript. Whenever I get confused by a piece of code, I try to make the syntax simpler so that I can understand what's going on:
setTimeout(function() {console.log("ok function called")}, 2000);
Now, that's a compact piece of code, let's make the syntax simpler. The above code is the same as:
var a = function() {console.log("ok function called")};
setTimeout(a, 2000);
So what does that do? It will call the function a after 2 seconds.
Now let's take a look at:
setTimeout(function() {console.log("ok function called")}(), 2000);
// Note this ----------^^
That's the same as:
var b = function() {console.log("ok function called")}();
setTimeout(b, 2000);
which can further be simplified to:
var a = function() {console.log("ok function called")};
var b = a();
setTimeout(b, 2000);
So I hope you see what you're really passing to setTimeout. You're passing the return value of the function, not the function.

When you write
setTimeout(function (params) { return something; }(55), 2000);
what actually happens is something like this:
var _temp_func = function (params) { return something; };
var _temp = _temp_func(55);
setTimeout(_temp, 2000);
The anonymous function you have as a parameter to setTimeout is evaluated immediately, even before the call to setTimeout itself. In contrast to that, the actual parameter that ends up in _temp here is called with a delay. This is what happens in your last example.

setTimeout takes only function name without parenthesis.
correct syntax : setTimeout(Helloworld) - here you are setting function
incorrect syntax : setTimeout(HelloWorld()) - here you are calling function
or non IIFE function.
It's an IIFE that you are passing hence it is getting called immediately.
setTimeout(function (params) { return something; }(55), 2000);

Related

How to send discord messages after waiting 1 second

if (msg.content.toLowerCase() === "!start") {
var gov = setInterval(go, 1000);
var onev = setInterval(one, 1000);
var twov = setInterval(two, 1000);
function two(msg) {
msg.channel.send("https://i.imgur.com/JZOCg5l.png ");
}
function one(msg) {
msg.channel.send("https://i.imgur.com/gTK3Vhn.png ");
}
function go(msg) {
msg.channel.send("https://i.imgur.com/3iVfYIR.png ");
}
function two(msg) { }
function one(msg) { }
function go(msg) { }
msg.channel.sendFile("https://i.imgur.com/kOoyoZQ.png ").then(onev).then(twov).then(gov);
}
This is a very annoying task. I need to send these images about one second appart.
The current framework keeps giving me the following error:
C:\Users\maver\Documents\TestBot\testlev.js:197
msg.channel.sendFile("https://i.imgur.com/3iVfYIR.png ");
^
TypeError: Cannot read property 'channel' of undefined at Timeout.three [as _onTimeout]
(C:\Users\maver\Documents\TestBot\testlev.js:197:17)
at ontimeout (timers.js:478:11)
at tryOnTimeout (timers.js:302:5)
at Timer.listOnTimeout (timers.js:262:5)
I've tried this a multitude of different ways and am just about ready to throw in the towel.
Your syntax is slightly off. When you do function two(msg){... you are actually telling the function that you are going to pass it a new variable and that you want that variable called msg. Because of that, msg (in the context of your function) is undefined. You would have to pass in msg when you call the function from setInterval().
There are 2 ways you can bind msg to your function. The way that I personally like is this:
//...
var gov = setInterval(go.bind(null, msg), 1000);
var onev = setInterval(one.bind(null, msg), 1000);
var twov = setInterval(two.bind(null, msg), 1000);
//...
The .bind() function assigns the value of arguments. With the first argument of the function being called being the second argument of bind(). The first argument of bind() is what should be used as the value of this inside the function.
The other way to do this is with an anonymous function
//...
var gov = setInterval(function(){go(msg)}, 1000);
var onev = setInterval(function(){one(msg)}, 1000);
var twov = setInterval(function(){two(msg)}, 1000);
//...
Also note, setInterval() repeats a function call ever period. You may be looking for setTimeout() which would only fire the functions once after a delay.
When you use setInterval, you should know it will call the function, but will not provide any parameters to it (or even this). One way to fix it would be by using bind:
setInterval(go.bind(null, msg), 1000)
This would work, because bind() will create a new function where the parameters are "magically set in advance".
Another option in this case would be to simply not re-declare msg in the three functions - in that case, javascript will try to find msg from the outer scope, where it exists:
function two() {
msg.channel.send("https://i.imgur.com/JZOCg5l.png ");
}
Third, you shouldn't be using setInterval, but setTimeout, which will only call the function once.
The fourth problem you have is with timing. First, all three setTimeout calls happen at the same time, so all three functions will be called in one second (after 1000 millis). An easy fix would be simply:
setTimeout(go, 1000);
setTimeout(one, 2000);
setTimeout(two, 3000);
However, that will completely ignore how long it takes to send each message (which may or may not be what you want). If you wanted to wait a second after the previous message is sent, then you'd have to do something like:
msg.channel.sendFile("https://i.imgur.com/kOoyoZQ.png ").then(function() {
setTimeout(go, 1000);
});
function go() {
msg.channel.send("https://i.imgur.com/3iVfYIR.png").then(function() {
setTimeout(one, 1000);
});
}
// etc
That would be very tedious, as all the functions will look very similar. So a better approach would be to create a list of messages, then have a single function to send all of them:
var msgs = [
"https://i.imgur.com/kOoyoZQ.png",
"https://i.imgur.com/JZOCg5l.png",
"https://i.imgur.com/gTK3Vhn.png",
"https://i.imgur.com/3iVfYIR.png"
];
function sendMsgs(msgs, delay) {
if (msgs.length < 1) return; // we're done
var remain = msgs.slice(1);
var sendRemain = sendMsgs.bind(null, remain, delay);
msg.channel.send(msgs[0]).then(function() {
setTimeout(sendRemain, delay);
});
}
sendMsgs(msgs, 1000);
Your code is executed immediately because you have to maintain the value anf promises you are using is not correctly used.
You can do it as follows :
if (msg.content.toLowerCase() === "!start") {
var urls = ["https://i.imgur.com/kOoyoZQ.png",
"https://i.imgur.com/JZOCg5l.png",
"https://i.imgur.com/gTK3Vhn.png",
"https://i.imgur.com/3iVfYIR.png" ];
function gov(urls){
for(let k=0; k<urls.length;k++){
setTimeout(function() { msg.channel.send(k); },k*1000)
}
}
gov(urls);
}

Can I call a timeout function on the returned element in this if statement?

Can I call a timeout function on the returned element in this if statement?
var data = 'some stuff';
if(data){
return jQuery('<div class="thisDiv"></div>').html(data);
}
I've tried the following:
if(data){
setTimeout(function() {
return jQuery('<div class="thisDiv"></div>').html(data);
}, 100);
}
But I get this error in my console:
Uncaught TypeError: Cannot read property 'nodeType' of undefined
The return statement will return from the anonymous function you passed into the setTimeout function, not the function enclosing the scope of the if statement. Try passing a callback into the function containing the if statement, then calling that callback with the data as a parameter.
function delayedReturn(callback) {
if(data) {
setTimeout(function() {
callback(jQuery('<div class="thisDiv"></div>').html(data));
}, 100);
}
}
No. You cannot use setTimeout to delay when a function will return. It is not a sleep function. It puts a function on a queue to run later, it doesn't stop all processing for a period of time.
function a() {
return 1;
}
var x = a();
In the above you have a single function which has a return statement. The value it returns is assigned to x.
function b() {
setTimeout(function c() {
return 1;
}, 1000);
}
var y = b();
Now you have two functions. b has no return statement, so it returns undefined and undefined is stored in y.
b uses setTimeout to call c, and c has a return statement. setTimeout doesn't do anything with return values though, so the return value of c is discarded.
Any time you are dealing with asynchronous functions, you have to do something with the data inside the asynchronous callback (such as call another function and pass the data as an argument). There is no going back, it is too late for that.
You could return a Promise from b though. That would allow other code to use the value of y to bind event handlers that will fire when the timeout expires.
You certainly can, you'd need to remove the return and use a valid selector to target your div.
Something like this would work:
HTML
<div class="thisDiv">test</div>
Javascript:
var data = 'some stuff';
if(data){
setTimeout(function() {
jQuery('.thisDiv').html(data);
}, 100);
}
You can see it working here: https://jsfiddle.net/ckkz1wbf/
Question, Why are you using:
jQuery('<div class="thisDiv"></div>')
Are you try to create an element, if that the case, you could use delay from jquery.
function fn(){
var data = 'some stuff';
if(data){
return jQuery('<div class="thisDiv"></div>').delay(100).html(data);
}
}

Trying to understand the syntax of delay function

the delay function:Delays a function for the given number of milliseconds, and then calls it with the arguments supplied.
is written from underscore js. annotated source:
_.delay = function(func, wait) {
var args = slice.call(arguments, 2);
return setTimeout(function(){
return func.apply(null, args);
}, wait);
};
for the delay function to work, why we need to use slice method and call (arguments,2), what does this part do?
Please correct me if im wrong. the delay function first return setTimeout to perform the delay, and the setTimeout function return func.apply(null,args) to pass on all of the information from one function to another? but what is "null" doing here?
when we call a function using delay, it says:
var log = _.bind(console.log, console);
_.delay(log, 1000, 'logged later');
=> 'logged later' // Appears after one second.
im not sure how the optional argument 'logged later' works here since im not sure how bind method works here either? can you please give me a simpler example?
setTimeout executes code in window context, so you have to take care to provide the correct reference for this in the callback function. _.bind does it for you.
var MyObject = function() {
this.myVariable = 'accessible';
this.myMethod = function(message) {
console.log((this === window));
console.log(message + this.myVariable);
}
}
var myObject = new MyObject();
// it will throw an error, because the this.myVariable isn't accessible
_.delay(myObject.myMethod, 1000, 'the correct scope is: ');
// this will be binded to the correct scope
_.delay(_.bind(myObject.myMethod, myObject), 1000, 'the correct scope is: ');

What is wrong with this Javascript script?

I'm writing a simple timer this way:
function timer(init){
console.log(init);
setTimeout(function(init){
timer(init+1);
},1000);
}
timer(1);
It's a recursive function (Note: I am aware it is an infinite loop, just not important now). However as simple as it seems, it fails as the output of each interval is NaN, and not an increased number as expected.
The function is so simple that I cannot figure out what the issue is. What am I missing?
The problem here is that you are overriding the value of init by passing an argument to setTimeout's callback function.
function timer(init) {
console.log(init);
setTimeout(function() {
timer(init+1);
},1000);
}
timer(1);
This way the init value is the one you passed into the timer call.
The function body you're passing in to setTimeout is a callback function, no arguments are passed to it (because setTimeout doesn't pass any).
function timer(init) {
console.log(init);
setTimeout(function() {
timer(init + 1);
}, 1000);
}
timer(1);
The simplest way to do it would be something like this:
var t = 0;
function timer() {
console.log(++t);
setTimeout(timer, 1000);
}
timer();
You need to feed an anonymous function as a parameter instead of a string, the latter method shouldn't even work per the ECMAScript specification but browsers are just lenient.
setTimeout(function() {
timer(init+1);
}, 1000)

How to pass arguments to a function in setTimeout

I have the following code:
function fn($){
return function(){
innerFn = function(){
setTimeout(show, 1000);
};
show = function(){
$.alert("TEST");
}
}
}
But, after one second, when the function show is run, it says $ is undefined. How do I resolve this issue?
how to pass arguments to a function in setTimeout
setTimeout has a built in mechanism for adding params
var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);
use it.
If you're going to use this - you should be careful. but that's another question.
There are a number of things at play here. The most important being that your setTimeout never gets called, since innerFn never gets called. This should do the trick.
function fn($){
return function(){
setTimeout(function(){
$.alert("TEST");
}, 1000);
}
}
fn(window)(); //triggers your alert after 1000ms
Your code makes no any sense, because nothing is called:
function fn($){
return function(){
innerFn = function(){
setTimeout(show, 1000);
};
show = function(){
$.alert("TEST");
}
}
}
Let's say I'm calling fn passing window, then a function is returned, that I can executed. But because this function is containing only function declaration - you also forget var so you pollute the global scope, that is bad - nothing is happen.
You'll need at least one function call inside, like:
function fn($){
return function(){
var innerFn = function(){
setTimeout(show, 1000);
};
var show = function(){
$.alert("TEST");
}
innerFn();
}
}
fn(window)();
And that will works. However, it's definitely redundant. You can just have:
function fn($){
return function(){
function show(){
$.alert("TEST");
}
setTimeout(show, 1000);
}
}
To obtain the same result. However, if you're goal is just bound an argument to setTimeout, you can use bind. You could use the 3rd parameter of setTimeout as the documentation says, but it seems not supported in IE for legacy reason.
So, an example with bind will looks like:
function show() {
this.alert('test');
}
setTimeout(show.bind(window), 1000);
Notice also that window is the global object by default, so usually you do not have to do that, just alert is enough. However, I suppose this is not your actual code, but just a mere test, as the alert's string says.
If you prefer having window as first parameter instead, and you're not interested in the context object this, you can do something like:
function show($) {
$.alert('test');
}
setTimeout(show.bind(null, window), 1000);

Categories

Resources