its a server side Javascript (rhino engine), so setTimeout is not available. how to run a function asynchronously?
You can use java.util.Timer and java.util.TimerTask to roll your own set/clear Timeout and set/clear Interval functions:
var setTimeout,
clearTimeout,
setInterval,
clearInterval;
(function () {
var timer = new java.util.Timer();
var counter = 1;
var ids = {};
setTimeout = function (fn,delay) {
var id = counter++;
ids[id] = new JavaAdapter(java.util.TimerTask,{run: fn});
timer.schedule(ids[id],delay);
return id;
}
clearTimeout = function (id) {
ids[id].cancel();
timer.purge();
delete ids[id];
}
setInterval = function (fn,delay) {
var id = counter++;
ids[id] = new JavaAdapter(java.util.TimerTask,{run: fn});
timer.schedule(ids[id],delay,delay);
return id;
}
clearInterval = clearTimeout;
})()
Have a look at the Multithreaded Script Execution example on the Rhino Examples page. Basically, JavaScript does not support threading directly, but you may be able to use a Java thread to achieve what you are looking for.
Another version using ScheduledThreadPoolExecutor, compatible with Rhino 1.7R4 and proposed by #Nikita-Beloglazov:
var setTimeout, clearTimeout, setInterval, clearInterval;
(function () {
var executor = new java.util.concurrent.Executors.newScheduledThreadPool(1);
var counter = 1;
var ids = {};
setTimeout = function (fn,delay) {
var id = counter++;
var runnable = new JavaAdapter(java.lang.Runnable, {run: fn});
ids[id] = executor.schedule(runnable, delay,
java.util.concurrent.TimeUnit.MILLISECONDS);
return id;
}
clearTimeout = function (id) {
ids[id].cancel(false);
executor.purge();
delete ids[id];
}
setInterval = function (fn,delay) {
var id = counter++;
var runnable = new JavaAdapter(java.lang.Runnable, {run: fn});
ids[id] = executor.scheduleAtFixedRate(runnable, delay, delay,
java.util.concurrent.TimeUnit.MILLISECONDS);
return id;
}
clearInterval = clearTimeout;
})()
Reference: https://gist.github.com/nbeloglazov/9633318
Related
I'm trying to cancel a requestAnimationFrame loop, but I can't do it because each time requestAnimationFrame is called, a new timer ID is returned, but I only have access to the return value of the first call to requestAnimationFrame.
Specifically, my code is like this, which I don't think is entirely uncommon:
function animate(elem) {
var step = function (timestamp) {
//Do some stuff here.
if (progressedTime < totalTime) {
return requestAnimationFrame(step); //This return value seems useless.
}
};
return requestAnimationFrame(step);
}
//Elsewhere in the code, not in the global namespace.
var timerId = animate(elem);
//A second or two later, before the animation is over.
cancelAnimationFrame(timerId); //Doesn't work!
Because all subsequent calls to requestAnimationFrame are within the step function, I don't have access to the returned timer ID in the event that I want to call cancelAnimationFrame.
Looking at the way Mozilla (and apparently others do it), it looks like they declare a global variable in their code (myReq in the Mozilla code), and then assign the return value of each call to requestAnimationFrame to that variable so that it can be used any time for cancelAnimationFrame.
Is there any way to do this without declaring a global variable?
Thank you.
It doesn't need to be a global variable; it just needs to have scope such that both animate and cancel can access it. I.e. you can encapsulate it. For example, something like this:
var Animation = function(elem) {
var timerID;
var step = function() {
// ...
timerID = requestAnimationFrame(step);
};
return {
start: function() {
timerID = requestAnimationFrame(step);
}
cancel: function() {
cancelAnimationFrame(timerID);
}
};
})();
var animation = new Animation(elem);
animation.start();
animation.cancel();
timerID; // error, not global.
EDIT: You don't need to code it every time - that's why we are doing programming, after all, to abstract stuff that repeats so we don't need to do it ourselves. :)
var Animation = function(step) {
var timerID;
var innerStep = function(timestamp) {
step(timestamp);
timerID = requestAnimationFrame(innerStep);
};
return {
start: function() {
timerID = requestAnimationFrame(innerStep);
}
cancel: function() {
cancelAnimationFrame(timerID);
}
};
})();
var animation1 = new Animation(function(timestamp) {
// do something with elem1
});
var animation2 = new Animation(function(timestamp) {
// do something with elem2
});
I am creating a wrapper function which will take array of functions and executes every function in a parallel manner so thought of using setTimeout but still functions are running sequentially. I suspect it could be because of closure that is being used to call SetTimeout. But why does it matter since setTimeout is async anyway?
// some blocking functionality
var withDelay = function (a) {
var currentTime = new Date().getTime(), delay = 5000;
while (currentTime + delay >= new Date().getTime()) {
}
console.log(a+"I am with delay");
}
// some non blocking functionality
var withoutDelay = function(a) {
console.log(a+"I am with no delay");
}
var fnArr = [withDelay, withoutDelay]; //array of functions
var args = ["Hi,"]; // arbitrary params
for( var i=0; i < fnArr.length; i++) {
var fn = fnArr[i];
(function(f,arg) {
return setTimeout(function(){ return f.apply(f,arg) },0);
})(fn,args)
}
Expected output:
Hi,I am with no delay
Hi,I am with delay
but Actual output is:
Hi,I am with delay
Hi,I am with no delay
JS runs on a single thread, Your function will not run parallelly. It will only run one at a time. Since you have scheduled both the functions with 0 delay as soon the first function from fnArr array viz. withDelay will run first. Only when this will complete its execution, the second function withoutDelay will start its execution. setTimeout will not guarantee your execution after provided interval, it is the minimum interval after which your function will execute. You can read more about setTimeout here
While loop doesnot delay a function you need to use setTimeout in your withDelay() and it working fine
var withDelay = function (a) {
setTimeout(() => {console.log(a+"I am with delay")},5000);
}
// some non blocking functionality
var withoutDelay = function(a) {
console.log(a+"I am with no delay");
}
var fnArr = [withDelay, withoutDelay]; //array of functions
var args = ["Hi,"]; // arbitrary params
for( var i=0; i < fnArr.length; i++) {
var fn = fnArr[i];
(function(f,arg) {
return setTimeout(function(){ return f.apply(f,arg) },0);
})(fn,args)
}
An example to call functions in a line after delay. As asked by questioner.
function func1(){
console.log("Function 1 is executed");
console.timeEnd('t');
}
function func2(){
console.log("Function 2 is executed");
console.timeEnd('t');
}
function func3(){
console.log("Function 3 is executed");
console.timeEnd('t');
}
let arrr = [
{func:func1,delay:2000},
{func:func2,delay:2000},
{func:func3,delay:3000},
]
async function callWithDelay(funcArr){
for(let func of funcArr){
//just to see time in console not necesarry
console.time('t');
//create a promise
let promise = new Promise((resolve,reject) => {
//'promise' will resolve after the function inside following code will end
setTimeout(()=>
{
resolve();
func.func();
},func.delay)
})
//The code will not proceed until the 'promise' is resolved(func is excecuted);
let x = await promise;
}
console.log("All the functions are excecuted");
}
callWithDelay(arrr);
I am having a hard time getting a countdown timer working as I don't know what I am doing wrong. I am trying to setup a countdown timer using jQuery in a prototype.
The main problem I see so far is at the setInterval:
_self.counter = setInterval(_self.runTimer(_self),1000);
When I don't pass in the "this" I get NaN but when I do the countdown only happens once and then stops.
Here is my JSFiddle work so far:
http://jsfiddle.net/f9GN7/
Thank you in advance.
I've modified a little of your code, I changed setInterval to setTimeout.
var timer_code = function(){
this.counter;
this.timeCountDown = 30;
}
timer_code.prototype = {
init : function(){
var _self = this;
$('#start').on('click',function(e){
_self.setTimer();
});
},
setTimer : function(){
var _self = this;
// _self.counter = setInterval(_self.runTimer(_self),1000);
var timerLoop = function(){
if(_self.timeCountDown > 0){
_self.runTimer();
setTimeout(timerLoop, 1000);
}
};
timerLoop();
},
runTimer : function(){
var _self = this;
_self.timeCountDown--;
if(_self.timeCountDown <= 0){
// clearInterval(_self.counter);
$('#timer').html("DONE");
return;
}
$('#timer').html(_self.timeCountDown);
console.log(_self.timeCountDown);
}
}
var timer = new timer_code();
timer.init();
http://jsfiddle.net/f9GN7/1/
setInterval gets a function reference as its first parameter ..
This function may not return a function object, the function call you just passed needs to be called in the scoope of a closure
Keeping your code with just a few modifications :
setTimer: function(){
if(this.counter)
clearInterval(this.counter); // timer may have already been launched, it may need to be cleared if its value is an integer and is != 0
this.counter = setInterval(
(function (ref) {
return function () {
ref.runTimer();
}
})(this),
1000);
}
See Fiddle Here
Let's assume that I have the timeout ID returned from setTimeout or setInterval.
Can I get, in some way, the original function or code, associated with it?
Something like this:
var timer_id = setTimeout(function() {
console.log('Hello Stackoverflowers!');
}, 100000);
var fn = timer_id.get_function(); // desired method
fn(); // output: 'Hello Stackoverflowers!'
You can put a wrapper around setTimeout - I just threw this one together (after a few iterations of testing...)
(function() {
var cache = {};
var _setTimeout = window.setTimeout;
var _clearTimeout = window.clearTimeout;
window.setTimeout = function(fn, delay) {
var id = _setTimeout(function() {
delete cache[id]; // ensure the map is cleared up on completion
fn();
}, delay);
cache[id] = fn;
return id;
}
window.clearTimeout = function(id) {
delete cache[id];
_clearTimeout(id);
}
window.getTimeout = function(id) {
return cache[id];
}
})();
NB: this won't work if you use a string for the callback. But no one does that, do they..?
Nor does it support passing the ES5 additional parameters to the callback function, although this would be easy to support.
var timeouts = {}; // hold the data
function makeTimeout (func, interval) {
var run = function(){
timeouts[id] = undefined;
func();
}
var id = window.setTimeout(run, interval);
timeouts[id] = func;
return id;
}
function removeTimeout (id) {
window.clearTimeout(id);
timeouts[id]=undefined;
}
function doTimeoutEarly (id) {
func = timeouts[id];
removeTimeout(id);
func();
}
var theId = makeTimeout( function(){ alert("here"); }, 10000);
console.log((timeouts[theId] || "").toString());
timeouts[theId](); // run function immediately, will still run with timer
You can store each timeout function in an object so that you can retrieve it later.
var timeout_funcs = {};
function addTimeout(func,time) {
var id = window.setTimeout(func,time);
timeout_funcs[id] = func;
return id;
}
function getTimeout(id) {
if(timeout_funcs[id])
return timeout_funcs[id];
else
return null;
}
function delTimeout(id) {
if(timeout_funcs[id]) {
window.clearTimeout(timeout_funcs[id]);
delete timeout_funcs[id];
}
}
the IDs returned from setTimeout/setInterval are just numbers, they have no properties or methods other than those that every other number would have. If you want to get that function, you can declare it first instead of using an anonymous:
var myFunc = function() {
console.log('Hello Stackoverflowers!');
};
var timer_id = setTimeout(myFunc, 100000);
myFunc(); // output: 'Hello Stackoverflowers!'
clearTimeout(timer_id); // unless you want it to fire twice
I am trying to overwrite timer methods (setTimeout, clearTimeout, setInterval and clearInterval) on an MSHTML instance, so I can track functions that have been added to setTimeout/setInterval and block the script from exiting until those functions have been called or removed.
I am getting a Permission denied error when the original setTimeout is called within the wrapper setTimeout function:
var window = new ActiveXObject('htmlfile').parentWindow.window;
var _setTimeout = window.setTimeout;
var timeouts = {};
setTimeout = function (code, ms, lang) {
//script fails here - Permission denied
var id = _setTimeout(code, ms, lang || 'javascript');
timeouts[id] = true;
return id;
};
setTimeout(function () {
window.alert('Timed function');
}, 1000);
var testTimeouts = function () {
var i;
for (i in timeouts) {
if (timeouts[i]) {return false;}
}
};
while (!testTimeouts()) {
WScript.Sleep(100);
}
window.alert('At end of script');
I can pass code to the original setTimeout before it's been overwritten:
window.setTimeout(function () {
window.alert('Timed function');
}, 1000);
WScript.Sleep(2500);
window.alert('At end of script');
Preserving the original context (as suggested in an answer that seems to have vanished) doesn't work:
window._setTimeout = window.setTimeout;
var timeouts = {};
window.setTimeout = function (code, ms, lang) {
var id = window._setTimeout(code, ms, lang || 'javascript');
timeouts[id] = true;
return id;
};
window.setTimeout(function () {
window.alert('Timed function');
}, 1000);
It fails at the call to window._setTimeout with Object doesn't support this property or method.
I should note that I am running IE8, WinXP SP3, JScript 5.8.
Why don't you call setTimeout from the window that you have stored?
var setTimeout;
var timeouts = {};
(function() {
var window = new ActiveXObject('htmlfile').parentWindow;
setTimeout = function(code, delay, lang){
var id = window.setTimeout(code, delay, lang || 'javascript');
timeouts[id] = true;
return id;
};
})();