setTimeout not working in windows script (jscript) - javascript

When I try to run the following code in my program
setTimeout("alert('moo')", 1000);
I get the following error
Error: Object expected
Code: 800A138F
Source: Microsoft JScript runtime error
Why? Am I calling the wrong function? What I want to do is delay the execution of the subsequent function.

It sounds like you're using setTimeout in a non-browser-based script (Windows Script Host or similar). You can't do that. You can, however, use WScript.Sleep to suspend your script briefly, with which you can achieve a similar effect. Also, alert is not a WSH function; you may want WScript.Echo. More on the WSH reference on MSDN.

setTimeout is a method of the window object provided by web browsers. It's not available to scripts running on Windows Script Host. Those scripts have a single thread of execution from start to finish and have no delay timers.
If you want to pause script execution you can use the Sleep method of the WScript object.

I needed WSH to behave like similar code in browser that uses setTimeout, so here's what I came up with.
Just have your single thread execute everything in a queue. You can keep adding to the queue. The program will only terminate when no functions are left in the queue.
It doesn't support strings for eval, just functions.
function main() {
Test.before();
_setTimeout(Test.timeout1, 1000);
_setTimeout(Test.timeout2, 2000);
_setTimeout(Test.timeout3, 500);
_setTimeout(Test.error, 2001);
Test.after();
}
var Test = function() {
var ld = "---- ";
var rd = " ----";
return {
before : function() {
log(ld + "Before" + rd);
},
after : function() {
log(ld + "After" + rd);
},
timeout1 : function() {
log(ld + "Timeout1" + rd);
},
timeout2 : function() {
log(ld + "Timeout2" + rd);
},
timeout3 : function() {
log(ld + "Timeout3" + rd);
},
error : function() {
log(ld + "error" + rd);
errorFunc();
}
};
}();
var FuncQueue = function() {
var funcQueue = [];
function FuncItem(name, func, waitTil) {
this.name = name;
this.func = func;
this.waitTil = waitTil;
}
return {
add : function(func, name, waitTil) {
funcQueue.push(new FuncItem(name, func, waitTil));
},
run : function() {
while (funcQueue.length > 0) {
var now = new Date().valueOf();
for ( var i = 0; i < funcQueue.length; i++) {
var item = funcQueue[i];
if (item.waitTil > now) {
continue;
} else {
funcQueue.splice(i, 1);
}
log("Executing: " + item.name);
try {
item.func();
} catch (e) {
log("Unexpected error occured");
}
log("Completed executing: " + item.name);
break;
}
if (funcQueue.length > 0 && i > 0) {
if (typeof (WScript) != "undefined") {
WScript.Sleep(50);
}
}
}
log("Exhausted function queue");
}
}
}();
function _setTimeout(func, delayMs) {
var retval = undefined;
if (typeof (setTimeout) != "undefined") {
retval = setTimeout(func, delayMs); // use the real thing if available
} else {
FuncQueue.add(func, "setTimeout", new Date().valueOf() + delayMs);
}
return retval;
}
var log = function() {
function ms() {
if (!ms.start) {
ms.start = new Date().valueOf();
}
return new Date().valueOf() - ms.start; // report ms since first call to function
}
function pad(s, n) {
s += "";
var filler = " ";
if (s.length < n) {
return filler.substr(0, n - s.length) + s;
}
return s;
}
return function(s) {
if (typeof (WScript) != "undefined") {
WScript.StdOut.WriteLine(pad(ms(), 6) + " " + s);
} else {
// find a different method
}
}
}();
FuncQueue.add(main, "main");
FuncQueue.run();

For anybody who is searching for the alert function to work in a stand-alone script (Windows Script Host environment), I recommend checking out jPaq's alert function which is documented here and downloadable here. I have definitely found this new library to be helpful for my stand-alone scripts.

Related

Javascript pausing timer woes... Can't calculate it

I've built a series of timers that are designed to be started, paused and resumed on cue. Numbers update dynamically on my page when the timer ticks up. The issue I'm having is figuring out how to get the timer to start from where it left off before I paused it. I can get it to restart from scratch, but I unsure how to take the paused Date.now() value, and work it into the formula to display the correct value. It will be something stupid that I just cant figure out.
function ticking2(num) {
//IF TIMER IS PAUSED CANCEL THE ANIMATION FRAME
if (timerObjArray[num].paused == true) {
timerObjArray[num].restartTime = Date.now();
cancelAnimationFrame(id);
} else if (timerObjArray[num].paused == false) {
timerObjArray[num].initialTime = Date.now()
if (timerObjArray[num].restartTime != 0) {
//THIS IS THE LINE WHERE I AM HAVING TROUBLE
timerObjArray[num].milli = ((timerObjArray[num].initialTime - timerObjArray[num].initialDate) - (timerObjArray[num].initialTime - timerObjArray[num].restartTime)) / 1000;
} else {
timerObjArray[num].milli = ((timerObjArray[num].initialTime - timerObjArray[num].initialDate ) / 1000);
}
//THIS FUNCTION TAKES THE MS VALUE AND CONVERTS IT TO HH:MM:SS
convert(num, timerObjArray[num].milli * 1000);
id = requestAnimationFrame(function() {
ticking2(num);
});
}
}
Thanks for the help.
I don't have enough information so, I made a simple implementation. You can look at this to help determine what you're missing. You're welcome to use it.
Timer fiddle
Utility:
var timer = (function() {
let _timers = {};
let pub = {
start : function(id) {
if(!_timers[id]) _timers[id] = {on:true, intervals:[{start:new Date()}] };
else if(_timers[id].on) throw 'timer is already started: ' + id;
else {
_timers[id].on = true;
_timers[id].intervals.push({start:new Date()});
}
},
stop : function(id) {
if(!_timers[id]) throw 'timer does not exist, cannot be stopped: ' + id;
else if(!_timers[id].on) throw 'timer is already stopped: ' + id;
else {
_timers[id].on = false;
let interval = _timers[id].intervals[_timers[id].intervals.length -1];
interval.stop = new Date();
interval.total = interval.stop - interval.start;
}
},
read : function(id) {
if(!_timers[id]) throw 'timer does not exist, cannot be read: ' + id;
let total = 0;
for(let i=0; i<_timers[id].intervals.length; i++) {
if(_timers[id].intervals[i].total) total += _timers[id].intervals[i].total;
else total += (new Date()) - _timers[id].intervals[i].start;
}
return { intervals:_timers[id].intervals, total: total };
},
delete: function(id) {
if(!_timers[id]) throw 'timer does not exist, cannot be deleted: ' + id;
delete _timers[id];
}
};
return pub;
})();
Example usage:
$('.start').on('click', function(){
timer.start(123);
});
$('.stop').on('click', function(){
timer.stop(123);
});
$('.clear').on('click', function(){
timer.delete(123);
$('input').val('');
});
setInterval(function(){
let result = null;
try//obviously not a great pattern
{
result = timer.read(123);
} catch(ex){}
if(result) {
$('input').val(result.total);
}
}, 35);

async and set timeout

I am having some problem using the settimeout() in my function. I am new to async. No matter how much I try I just can't make the timeout work. My code works perfect so that is not the problem. I need the request to execute every 10 seconds. Thanks for the help.
function getContent() {
function getPelicula(pelicula, donePelicula) {
var peli = pelicula.title;
//request id
request({
url: "http://api.themoviedb.org/3/search/movie?query=" + peli + "&api_key=3e2709c4c051b07326f1080b90e283b4&language=en=ES&page=1&include_adult=false",
method: "GET",
json: true,
}, function(error, res, body) {
if (error) {
console.error('Error getPelicula: ', error);
return;
}
var control = body.results.length;
if (control > 0) {
var year_base = pelicula.launch_year;
var id = body.results[0].id;
var year = body.results[0].release_date;
var d = new Date(year);
var year_solo = d.getFullYear();
if (year_base == year_solo) {
pelicula.id = id;
pelicula.year_pagina = year_solo;
}
} else {
pelicula.id = null;
pelicula.year_pagina = null;
}
donePelicula();
});
}
}
To do something in a loop, use setInterval.
UPD:
In general, there're two ways of executing some code in loop
1 setTimeout :
var someTimer = setTimeout(function sayHello(){
console.log("hello!");
someTimer = setTimeout(sayHello, 2000);
}, 2000);
Notice that someTimer variable is needed to stop the looping process if you need: clearTimeout(someTimer)
2 setInterval:
var someIntervalTimer = setInterval(function(){
console.log("I'm triggered by setInterval function!");
}, 2000);
Invoke clearInterval(someIntervalTimer) to stop the looping
Both functions are treated as properties of the global Window variable. By default, the following code works:
var window = this;
console.log("type of setTimeout: " + typeof window.setTimeout);
console.log("type of setInterval: " + typeof window.setInterval);
Try putting it in another function so:
domore(pelicula,donePelicula);
function domore(pelicula,donePelicula) {
// 1 second
var timeout = 1000;
for (var i = 1; i < pelicula.length; i++) {
createData(pelicula[i],donePelicula,timeout);
timeout = timeout + 800;
}
}
function createData(peli,donePelicula,timeout) {
setTimeout(function() { getData(peli,donePelicula); }, timeout);
}
function getData(peli,donePelicula) {
var txtFile = new XMLHttpRequest();
txtFile.open("GET", "http://api.themoviedb.org/3/search/movie?query=" + peli + "&api_key=3e2709c4c051b07326f1080b90e283b4&language=en=ES&page=1&include_adult=false", true);
txtFile.onreadystatechange = function() {
if (txtFile.readyState === 4) { // Makes sure the document is ready to parse.
if (txtFile.status === 200) { // Makes sure it's found the file.
allText = txtFile.responseText;
domore(allText,donePelicula);
}
}
}
txtFile.send(null);
}

How to delay a JavaScript JSON stream for one minute?

I am ask to write a java script program that retrieve an api JSON record from and address and through websocket every single minute. The stream continues after 60 seconds. I am expected to return the respective stream retrieve and the stream from the previous retrieve . Below is my code
var obj=
{
seconds : 60,
priv : 0,
prevTick : '' ,
data : ''
}
function countTime()
{
obj.seconds --;
obj.priv ++;
var msg ;
if(obj.priv > 1)
{
obj.priv = 0;
obj.msg = null;
}
if(prop.seconds < 0)
{
msg = sock.open();
obj.msg = obj.msg + ", New Tick : " + msg.msg ;
setTimeout(countTime, 1000);
obj.seconds = 60;
}
}
var sock= new WebSocket('link');
sock.onopen = function(evt) {
ws.send(JSON.stringify({ticks:'string'}));
};
sock.onmessage = function(msg) {
var data = JSON.parse(msg.data);
return 'record update: %o'+ data ;
};
Please what is wrong with my code above ? It does not delay at all. The stream continues irrespective.
How about encapsulating the buffering behavior into a class?
function SocketBuffer(socket, delay, ontick) {
var messages = [], tickInterval;
socket.onmessage = function(msg) {
messages.push( JSON.parse(msg.data) );
};
function tick() {
if (typeof ontick !== "function") return;
ontick( messages.splice(0) );
}
this.pause = function () {
tickInterval = clearInterval(tickInterval);
};
this.run = function () {
if (tickInterval) return;
tickInterval = setInterval(tick, delay * 1000);
tick();
};
this.run();
}
Note that .splice(0) returns all elements from the array and empties the array in the same step.
Usage:
var link = new WebSocket('link');
link.onopen = function (evt) {
this.send( JSON.stringify({ticks:'string'}) );
};
var linkBuf = new SocketBuffer(link, 60, function (newMessages) {
console.log(newMessages);
});
// if needed, you can:
linkBuf.pause();
linkBuf.run();
Try this:
function countTime() {
var interval = 1000; // How long do you have to wait for next round
// setInterval will create infinite loop if it is not asked to terminate with clearInterval
var looper = setInterval(function () {
// Your code here
// Terminate the loop if required
clearInterval(looper);
}, interval);
}
If you use setTimeout() you don't need to count the seconds manually. Furthermore, if you need to perform the task periodically, you'd better use setInterval() as #RyanB said. setTimeout() is useful for tasks that need to be performed only once. You're also using prop.seconds but prop doesn't seem to be defined. Finally, you need to call countTime() somewhere or it will never be executed.
This might work better:
var obj=
{
seconds : 60,
priv : 0,
prevTick : '' ,
data : ''
}
function countTime()
{
obj.seconds --;
obj.priv ++; //I don't understand this, it will always be set to zero 3 lines below
var msg ;
if(obj.priv > 1)
{
obj.priv = 0;
obj.msg = null;
}
msg = sock.open();
obj.msg = obj.msg + ", New Tick : " + msg.msg;
obj.seconds = 60;
//Maybe you should do sock.close() here
}
var sock= new WebSocket('link');
sock.onopen = function(evt) {
ws.send(JSON.stringify({ticks:'string'}));
};
sock.onmessage = function(msg) {
var data = JSON.parse(msg.data);
return 'record update: %o'+ data ;
};
var interval = setInterval(countTime, 1000);
EDIT: finally, when you're done, just do
clearInterval(interval);
to stop the execution.

NodeJS Background jobs never execute, loop forever

I have a module that starts some background jobs in NodeJS (the jobs are HTTP requests), here is a simplified version of it:
var
util = require('util'),
EE = require('events').EventEmitter,
Winston = require('winston');
var logger = new Winston.Logger({transports: [new Winston.transports.Console()]});
function Bot() {
EE.call(this);
this.model = ['job1','job2','job3'];
// null = never had a job, false = job started, true = job finished
this.jobs = {
'job1': null,
'job2': null,
'job3': null };
var mirror = this;
function start_job(job) {
var t = Math.floor(Math.random() * 10 + 1) * 1000;
logger.info('calling ' + job + ' for t=' + t);
setTimeout(function() {
logger.info('finished ' + job);
mirror.jobs[job] = true;
}, t);
}
this.on('start', function() {
logger.info('Starting');
while (mirror.isRunning()) {
for (var i=0; i<mirror.model.length; i++) {
var job = mirror.model[i];
var oldJob = mirror.jobs[job];
if (oldJob === null || oldJob === true) {
mirror.jobs[job] = false;
start_job(job);
}
}
// mirror.shutdown();
}
logger.info('Shutting down');
});
}
util.inherits(Bot, EE);
Bot.prototype.shutdown = function() {
this.running = false;
};
Bot.prototype.start = function() {
this.running = true;
this.emit('start');
};
Bot.prototype.isRunning = function() {
return this.running;
};
var bot = new Bot();
bot.start();
The problem is that the jobs never actually run. start_job() is called but the anon function in setTimeout() never fires. Here is the output:
info: Starting
info: calling job1 for t=6000
info: calling job2 for t=5000
info: calling job3 for t=9000
The script hangs up at this point, in an infinite loop.
Now, if I stop after the first loop iteration, by uncommenting mirror.shutdown(), the jobs start as expected:
info: Starting
info: calling job1 for t=6000
info: calling job2 for t=9000
info: calling job3 for t=1000
info: Shutting down
info: finished job3
info: finished job1
info: finished job2
But that is no good. I have no idea why this is happening, but I'm new to Node and still struggling with some concepts.
I know of a module called Background.js, but I don't know if this would be applicable here or how stable to is (doesn't seem to be an active project). I could try it but I still want to understand this problem before moving on.
The problem is that node.js is single-threaded. That while loop continues running and hogs the event loop, so the setTimeout doesn't have a chance to fire. Instead of a while loop to start jobs, you'll want to put that on a setInterval (or possibly a recursive setTimeout). For example:
this.on('start', function() {
logger.info('Starting');
for (var i=0; i<mirror.model.length; i++) {
var job = mirror.model[i];
var oldJob = mirror.jobs[job];
if (oldJob === null || oldJob === true) {
mirror.jobs[job] = false;
start_job(job);
}
}
setTimeout(function(){mirror.start()}, 50);
logger.info('Shutting down');
});

Javascript Preloading images on iPad

My preloader seems unstable on iPad, even though it works perfectly in all major browsers on both PC and MAC.
Sometimes it works, sometimes it don't, but if I clear the cache, it allmost allways fails on first try.. I'm really stuck here, so any help would be appreciated!
This is my code:
function preloadimages(arr){
var newimages=[], loadedimages=0
var postaction=function(){}
var arr=(typeof arr!="object")? [arr] : arr
function imageloadpost(){
loadedimages++
if (loadedimages==arr.length){
postaction(newimages) //call postaction and pass in newimages array as parameter
}
}
for (var i=0; i<arr.length; i++){
newimages[i]=new Image()
newimages[i].src=arr[i]
newimages[i].onload=function(){
imageloadpost()
}
newimages[i].onerror=function(){
imageloadpost()
}
}
return { //return blank object with done() method
done:function(f){
postaction=f || postaction //remember user defined callback functions to be called when images load
}
}
}
$(document).ready(function(){
preloadimages(['img/bg_joejuice.jpg',
'img/bg_facebook.jpg',
'img/bg_webshop.jpg',
'img/bg_spotify.jpg',
'img/btn_grey_down.png',
'img/btn_pink_down.png',
'img/coffee_active.png',
'img/juice_normal.png',
'img/sandwich_active.png',
'img/remove_down.png',
'img/inc_down.png',
'img/dec_down.png',
'img/checkbox_unchecked.png',
'img/hide_spotify.png',
'img/logo_facebook_active.png',
'img/logo_joejuice.png',
'img/logo_spotify_active.png',
'img/logo_webshop_active.png',
'img/checkbox_unchecked.png',]
).done(function(){
console.log("loaded");
});
});
EDIT:
Sorry for not specifying..
I get no errors in console (related), and it doesn't get to the point where it logs the "loaded" comment.
http://md4a1215.keaweb.dk
NEW EDIT
I got 19 pictures. It runs the forloop 19 times. When the error occur, I usually get 18 "onload" (but has seen as low as 16) and never any "onerror".
It looks like it's the onerror function that isn't triggered (allthough it DOES trigger i all major browsers on both MAC and PC, and it does trigger on the iPad if I just remove one of the images thst id included in the list).. Does this sound right? - And if it does, how can I get this to work?
Your code appears to increment loadedimages onerror as well as onload. Try something like this (this retries the preload on error, and skips the image if it fails maxattempts times)
function preloadimages(arr) {
var newimages = [], loadedimages=0, attempts = 0, maxattempts = 5;
var postaction=function(){};
var arr=(typeof arr!='object') ? [arr] : arr;
function imageloadpost(){
if (loadedimages == newimages.length){ console.log('Preloading of images complete. Loaded ' + newimages.length + ' images of ' + arr.length + '. Processing postaction.'); postaction(newimages); }
}
for (var i=0; i<arr.length; i++){
newimages[i]=new Image();
newimages[i].src=arr[i];
newimages[i].onload=function(){
console.log('Loaded ' + loadedimages + ' ' + this.src);
attempts=0;
loadedimages++;
imageloadpost();
};
newimages[i].onerror=function(){
attempts++;
if(attempts < maxattempts){
console.log('Failed to load: ' + this.src + ' trying again');
this.src = this.src;
}
else{
console.log('Skipping ' + this.src);
var tSrc = this.src;
var thisIndex = -1;
for(var i=0; i <arr.length; i++)
{
if(newimages[i].src === tSrc)
{
thisIndex = i;
}
}
attempts=0;
if(thisIndex >= 0)
{
console.log('Removing ' + tSrc + ' from image list due to failure to load.');
newimages.splice(thisIndex,1);
}
else
{
console.log('Error encountered, could not find ' + tSrc + ' in newimages.');
loadedimages++;
}
imageloadpost();
}
};
} //end of for loop
return { done: function(f) { postaction = f || postaction } }
}
$(document).ready(function(){
preloadimages(['img/image1.jpg','img/image2.jpg','img/image3.jpg']).done(function() { console.log('Function preloadimages is done'); });
});

Categories

Resources