Stop function from re- executing for one second with settimeout - javascript

I want to prevent my function from re-executing for one second after it's last executed. I've tried the method below, but it doesn't work.
function displayOut() {
// images
document.getElementById("imgBox").style.backgroundImage = "url(" + db.rooms[roomLoc].roomImg + ")";
// Diologue box
diologueBox.innerHTML = ""; // Clear Box
teleTyperDiologue(db.rooms[roomLoc].description +
" The room contains: " +
(function() {
let x = "";
for (let i = 0; i < db.items.length; i++) {
if (db.items[i].location === roomLoc && db.items[i].hidden === false) {
x += db.items[i].name + ", "
}
}
x = x.slice(0, x.length -2);
if (x === "") {
x = " nothing of special interest";
}
return x;
})()
+ ".");
pause();
};
function pause() {
setTimeout(function() {
// Wait one second!
}, 1000);
}

You could use a pattern like this:
var executing = false;
function myFunc() {
if(!executing) {
executing = true;
//Code
console.log('Executed!');
//End code
setTimeout(function() {
executing = false;
}, 1000);
}
}
setInterval(myFunc, 100);
So in your case, this would look like this:
var executing = false;
function displayOut() {
if(!executing) {
executing = true;
// images
document.getElementById("imgBox").style.backgroundImage = "url(" + db.rooms[roomLoc].roomImg + ")";
// Diologue box
diologueBox.innerHTML = ""; // Clear Box
teleTyperDiologue(db.rooms[roomLoc].description +
" The room contains: " +
(function() {
let x = "";
for (let i = 0; i < db.items.length; i++) {
if (db.items[i].location === roomLoc && db.items[i].hidden === false) {
x += db.items[i].name + ", "
}
}
x = x.slice(0, x.length -2);
if (x === "") {
x = " nothing of special interest";
}
return x;
})()
+ ".");
setTimeout(function() {
executing = false;
}, 1000);
}
};

Try to use throttle (http://underscorejs.org/#throttle) or debounce (http://underscorejs.org/#debounce) from underscore, one of those should fit your needs

This one will achieve that:
function run () {
console.log('Im running');
pause(1000);
};
function pause(s) {
console.log('Im paused');
setTimeout(() =>{
run();
}, s)
};
run();
The code above will run every 1 sec but if you want to make sure the function cant be runned again until you decide then you could use a flag instead like:
let canExecute = true;
function run () {
if (canExecute) {
console.log('Im running');
canExecute = false;
pause(1000);
}
};
function pause(s) {
console.log('Im paused');
setTimeout(() =>{
canExecute = true;
}, s)
};
run();
run();
run();
setTimeout(() =>{
run();
}, 2000)
This code will execute run function twice, first on time and then one more after 2 sec.

Related

How do I make A and B run in parallel?

How do I make A and B run in parallel?
async function runAsync(funcName)
{
console.log(' Start=' + funcName.name);
funcName();
console.log(' End===' + funcName.name)
};
function A()
{
var nowDateTime = Date.now();
var i = 0;
while( Date.now() < nowDateTime + 1000)
i++;
console.log(' A i= ' + i) ;
}
function B()
{
var nowDateTime = Date.now();
var i = 0;
while( Date.now() < nowDateTime + 1000)
i++;
console.log(' B i= ' + i) ;
}
runAsync(A);
runAsync(B);
The console shows that A starts first and B starts after A:
Start=A
A i= 6515045
End===A
Start=B
B i= 6678877
End===B
Note:
I am trying to use async for Chrome/Firefox, and keep the JS code compatible with IE11.
This C# code generates the proxy function runAsync:
if (isEI())
Current.Response.Write(" function runAsync(funcName){ setImmediate(funcName); }; ");
else
Current.Response.Write(" async function runAsync(funcName){ funcName(); } ");
https://jsfiddle.net/NickU/n2huzfxj/28/
Update.
My goal was to parse information and prepare (indexing and adding triggers) for an immediate response after user input. While the user is viewing the information, the background function has 3-10 seconds to execute, and the background function should not block UI and mouse and keyboard responses. Here is the solution for all browsers, including IE11.
Created a new Plugin to simulate parallel execution of funcRun during idle times.
Example of an original code:
$("input[name$='xxx'],...").each( function(){runForThis(this)}, ticksToRun );
The updated code using the Plugin:
$(document).zParallel({
name: "Example",
selectorToRun: "input[name$='xxx'],...",
funcRun: runForThis
});
Plugin.
(function ($)
{
// Plugin zParallel
function zParallel(options)
{
var self = this;
self.defaults = {
selectorToRun: null,
funcRun: null,
afterEnd: null,
lengthToRun: 0,
iterScheduled: 0,
ticksToRun: 50,
showDebugInfo: true
};
self.opts = $.extend({}, self.defaults, options);
}
zParallel.prototype = {
init: function ()
{
var self = this;
var selector = $(self.opts.selectorToRun);
self.lengthToRun = selector.length;
if (self.lengthToRun > 0)
{
self.arrayOfThis = new Array;
selector.each(function ()
{
self.arrayOfThis.push(this);
});
self.arrayOfThis.reverse();
self.opts.iterScheduled = 0;
self.whenStarted = Date.now();
self.run();
return true;
}
else
{
this.out('zParallel: selector is empty');
return false;
}
},
run: function ()
{
var self = this;
var nextTicks = Date.now() + self.opts.ticksToRun;
var _debug = self.opts.showDebugInfo;
if (self.opts.iterScheduled === 0)
{
nextTicks -= (self.opts.ticksToRun + 1); // Goto to Scheduling run
}
var count = 0;
var comOut = "";
while ((self.lengthToRun = self.arrayOfThis.length) > 0)
{
var curTicks = Date.now();
if (_debug)
{
comOut = self.opts.name + " |" + (curTicks - self.whenStarted)/1000 + "s| ";
if (self.opts.iterScheduled === 0)
this.out("START " + comOut + " remaining #" + self.lengthToRun);
}
if (curTicks > nextTicks)
{
self.opts.iterScheduled++;
if ('requestIdleCallback' in window)
{
if (_debug)
this.out(comOut + "requestIdleCallback , remaining #" + self.lengthToRun + " executed: #" + count);
window.requestIdleCallback(function () { self.run() }, { timeout: 1000 });
} else
{
if (_debug)
this.out(comOut + "setTimeout, remaining #" + self.lengthToRun + " executed: #" + count);
setTimeout(function (self) { self.run()}, 10, self);
}
return true;
}
var nexThis = self.arrayOfThis.pop();
self.opts.funcRun(nexThis);
count++;
}
if (self.opts.afterEnd!== null)
self.opts.afterEnd();
if (_debug)
this.out("END " + comOut + " executed: #" + count);
return true;
},
out: function (str)
{
if (typeof console !== 'undefined')
console.log(str);
}
};
$.fn.zParallel = function (options)
{
var rev = new zParallel(options);
rev.init();
};
})(jQuery);
// Examples.
(function ($)
{
var tab1 = $('#tbl1');
for (i = 0; i < 1000; i++)
$("<tr>"+
"<td>#" + i + "</td>"+
"<td><input id='a_" + i + "' value='" + i + "' >"+
"</td><td><input id='b_" + i + "' value='" + i + "' ></td></tr>")
.appendTo(tab1);
$(document).zParallel({
name: "A",
selectorToRun: "input[id^='a_']",
funcRun: function (nextThis)
{
var $this = $(nextThis);
var nowDateTime = Date.now();
var i = 0;
while( Date.now() < nowDateTime + 2)
i++;
$this.val( i );
if (i > 100)
$this.css('color', 'green').css('font-weight', 'bold');
else
$this.css('color', 'blue');
}
});
$(document).zParallel({
name: "B",
selectorToRun: "input[id^='b_']",
funcRun: function (nextThis)
{
var $this = $(nextThis);
var nowDateTime = Date.now();
var i = 0;
while( Date.now() < nowDateTime + 2)
i++;
$this.val( i );
if (i > 100)
$this.css('background', '#BBFFBB');
else
$this.css('background', '#FFBBBB');
}
});
})(jQuery);
https://jsfiddle.net/NickU/1xt8L7co/59/
The two example functions simply execute synchronously one after the other on the same "thread" (JS effectively has only one thread available to such scripts).
The use of async is irrelevant here because no truly asynchronous operation is occurring in function A - it is simply a busy while loop - so it completes in full before execution can move to anything else.
If function A had called an actual asynchronous operation (such as a HTTP request - not simply a synchronous operation wrapped in an async function), then function B may have a chance to start up (in which case B would complete entirely before the execution returned to A, because B is also only contains a synchronous, busy while loop).
Parallel processing can be achieved with WebWorkers which allowing running on background threads (actual separate threads).

Calling setInterval multiple times then Clearing interval , polling not stopped

As my loop is so fast, the intervals are overlapping and not able to stop one timerId. here is my code:
data = ['115536', '117202']; // BARCODES AVAILABLE ON A4 SHEET //
var scan_delay = 500; // USER AVG SCANNING SPEED PER BARCODE //
var timerId;
var scannedItemsList = []; // ITEMS WHICH ARE SCANNED BY SEEING A4 SHEET BY THE USER //
var tableDataList = []; // TO SHOW DATA WHICH WE GOT FROM API //
Jbin
try {
var data = ['115536', '117202']; // BARCODES AVAILABLE ON A4 SHEET //
var scan_delay = 500; // USER AVG SCANNING SPEED PER BARCODE //
var timerId;
var scannedItemsList = []; // ITEMS WHICH ARE SCANNED BY SEEING A4 SHEET BY THE USER //
var tableDataList = []; // TO SHOW DATA WHICH WE GOT FROM API //
execute(data);
function execute(data) {
var i = 0;
scanSimulatorWithADelay(data, i);
}
function scanSimulatorWithADelay(data, i) {
setTimeout(function () {
getJobDetailsByCallingAPI(data[i], i);
i++;
if (data.length > i) {
scanSimulatorWithADelay(data, i);
} else {
i = 0;
}
}, scan_delay);
}
function getJobDetailsByCallingAPI(jobNumber, index) {
scannedItemsList.push(jobNumber);
//poll_for_jobs_count_which_are_scanned_but_waiting_to_add_to_table
startPolling();
//Simulate API to get response after every 3 seconds//
var apiDelay = (index + 1) * 3000;
setTimeout(function () {
console.log('API CALLED AT ' + new Date().toLocaleTimeString());
CallTheAPI(jobNumber);
}, apiDelay);
}
function CallTheAPI(jobNumber) {
console.log("JOB NO " + jobNumber + " API response Recd");
tableDataList.push(jobNumber);
}
function startPolling() {
var pollStatus = '';
timerId = setInterval(() => {
debugger;
console.log('timerId when starting interval ' + timerId);
var jobsWhichAreScannedButNotLoaded = jobsWhichAreScannedButNotLoadedStill();
console.log("$$$$$$ jobsWhichAreScannedButNotLoaded = " + jobsWhichAreScannedButNotLoaded.length);
if (jobsWhichAreScannedButNotLoaded.length === 0) {
console.log("### Inteval Cleared ### " + timerId);
//CLEAR TIMER
clearInterval(timerId);
} else {
pollStatus = 'Polling inprogress and the pollID ' + timerId;
}
console.log('####' + pollStatus);
}, 2000);
}
function jobsWhichAreScannedButNotLoadedStill() {
let stillLoadingJobs = [];
scannedItemsList.forEach(scannedItemsListJobNumber => {
let foundJobInsideTable = false;
if (scannedItemsListJobNumber) {
foundJobInsideTable = tableDataList.indexOf(scannedItemsListJobNumber) > -1;
if (!foundJobInsideTable) {
stillLoadingJobs.push(scannedItemsListJobNumber);
}
}
}); // End of scannedItemsList forEach loop
if (stillLoadingJobs.length > 0) {
return stillLoadingJobs;
}
return [];
}
} catch (error) { throw error; }
Your timer_id variable is on the global scope and hence overwritten every time you call startPolling.
So when you'll call clearInterval(timer_id), timer_id will be the id of the last setInterval, and the first one will keep running endlessly.
Simply add a var in your startPolling function so that timer_id be scoped correctly, and that it doesn't get overwritten by next call.
try {var data = ['115536', '117202'];
var scan_delay = 500;
// remove this one
//var timerId;
var scannedItemsList = [];
var tableDataList = [];
execute(data);
function execute(data) {
var i = 0;
scanSimulatorWithADelay(data, i);
}
function scanSimulatorWithADelay(data, i) {
setTimeout(function () {
getJobDetailsByCallingAPI(data[i], i);
i++;
if (data.length > i) {
scanSimulatorWithADelay(data, i);
} else {
i = 0;
}
}, scan_delay);
}
function getJobDetailsByCallingAPI(jobNumber, index) {
scannedItemsList.push(jobNumber);
//poll_for_jobs_count_which_are_scanned_but_waiting_to_add_to_table
startPolling();
//Simulate API to get response after every 3 seconds//
var apiDelay = (index + 1) * 3000;
setTimeout(function () {
console.log('API CALLED AT ' + new Date().toLocaleTimeString());
CallTheAPI(jobNumber);
}, apiDelay) ;
}
function CallTheAPI(jobNumber) {
$.ajax({
url: "https://jsonplaceholder.typicode.com/todos/1",
type: "GET",
async: true,
success: function (response) {
console.log("JOB NO " + jobNumber + " API response Recd");
tableDataList.push(jobNumber);
}
});
}
function startPolling() {
var pollStatus = '';
/////////
///HERE
/////////
// Declare timerId in startPolling scope
/////////
var timerId = setInterval(() => {
debugger;
console.log('timerId when starting interval '+ timerId);
var jobsWhichAreScannedButNotLoaded = jobsWhichAreScannedButNotLoadedStill();
console.log("$$$$$$ jobsWhichAreScannedButNotLoaded = "+ jobsWhichAreScannedButNotLoaded.length);
if (jobsWhichAreScannedButNotLoaded.length === 0) {
console.log("### Inteval Cleared ### "+ timerId);
//CLEAR TIMER
clearInterval(timerId);
} else {
pollStatus = 'Polling inprogress and the pollID ' + timerId;
}
console.log('####' + pollStatus);
}, 2000);
}
function jobsWhichAreScannedButNotLoadedStill() {
let stillLoadingJobs = [];
scannedItemsList.forEach(scannedItemsListJobNumber => {
let foundJobInsideTable = false;
if (scannedItemsListJobNumber) {
foundJobInsideTable = tableDataList.indexOf(scannedItemsListJobNumber) > -1;
if (!foundJobInsideTable) {
stillLoadingJobs.push(scannedItemsListJobNumber);
}
}
}); // End of scannedItemsList forEach loop
if (stillLoadingJobs.length > 0) {
return stillLoadingJobs;
}
return [];
}
} catch (error) { throw error; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Continuous calculations on-the-go in Javascript

I have a simple calculator made in JS and works well, but when I finish my calculation and get my result (i.e. pressing the "=" button), I want the returned result to be in a saved state. The "=" button must be ready to be clicked again, and get the same result, and then add it to the save result.
I've tried many obvious ways, such as adding the result to itself (which doesn't work because the result will be multiplied by itself, not added), exploiting the eval() function and adding a "+" string to the end result, etc.
TLDR: If you go to any calculator program, and type "2+2" and click equals, you get 4. If you click equals again, you get 6 ("2+2+2").
Here's my current code:
var disp = document.getElementById("calc-output"),
acceptedInputs = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, "-", ".", "+", "*", "/"];
function ud(n) {
if (acceptedInputs.includes(n)) {
if (disp.innerHTML.length == 31) {
disp.innerHTML = 0;
}
if (disp.innerHTML.length < 18) {
if (disp.innerHTML != 0) {
disp.innerHTML += n;
} else if (acceptedInputs.slice(11, -1).includes(n)) {
disp.innerHTML = 0 + n;
} else if (disp.innerHTML.toString().slice(1, 2) == ".") {
if (disp.innerHTML.toString().split(".").length-1 <= 1) {
disp.innerHTML += n;
}
} else {
disp.innerHTML = n;
}
}
}
}
function answer() {
if (eval(disp.innerHTML) == disp.innerHTML) {
disp.innerHTML = disp.innerHTML + "+"
}
c = eval(disp.innerHTML);
disp.innerHTML = c;
}
function clear() {
disp.innerHTML = "0";
}
function back() {
var str = disp.innerHTML.toString();
if (disp.innerHTML != 0 || str.charAt(1) == ".") {
if (str.length >= 2) {
str = str.slice(0, -1);
disp.innerHTML = str;
} else {
disp.innerHTML = 0;
}
}
}
document.getElementById("n1").addEventListener("click", function() {
ud(1);
});
document.getElementById("n2").addEventListener("click", function() {
ud(2);
});
document.getElementById("n3").addEventListener("click", function() {
ud(3);
});
document.getElementById("n4").addEventListener("click", function() {
ud(4);
});
document.getElementById("n5").addEventListener("click", function() {
ud(5);
});
document.getElementById("n6").addEventListener("click", function() {
ud(6);
});
document.getElementById("n7").addEventListener("click", function() {
ud(7);
});
document.getElementById("n8").addEventListener("click", function() {
ud(8);
});
document.getElementById("n9").addEventListener("click", function() {
ud(9);
});
document.getElementById("zero-button").addEventListener("click", function() {
ud(0);
});
document.getElementById("comma-button").addEventListener("click", function() {
ud('.');
});
document.getElementById("plus-button").addEventListener("click", function() {
ud('+');
});
document.getElementById("minus-button").addEventListener("click", function() {
ud('-');
});
document.getElementById("multi-button").addEventListener("click", function() {
ud('*');
});
document.getElementById("div-button").addEventListener("click", function() {
ud('/');
});
document.getElementById("back-button").addEventListener("click", function() {
back();
});
document.getElementById("clear-button").addEventListener("click", function() {
clear();
});
document.getElementById("equals-button").addEventListener("click", function() {
answer();
});
Save the last operation (e.g. " + 2") in some variable when user clicks equal. So, when he clicks again, just append saved value to the string from display.
var lastOperation = null;
function answer() {
if (eval(disp.innerHTML) == disp.innerHTML) {
// apply the last operation to displayed number
disp.innerHTML = disp.innerHTML + (lastOperation ? lastOperation[0] : '');
}
// find the last operation + | - | * | /
lastOperation = disp.innerHTML.split(new RegExp('(\\+|\\-|\\*|/).*$'));
c = eval(disp.innerHTML);
disp.innerHTML = c;
}

Return value inside a setInterval

I want to return a value inside a setInterval. I just want to execute something with time interval and here's what I've tried:
function git(limit) {
var i = 0;
var git = setInterval(function () {
console.log(i);
if (i === limit - 1) {
clearInterval(git);
return 'done';
}
i++;
}, 800);
}
var x = git(5);
console.log(x);
And it's not working.
Is there any other way?
What I'm going to do with this is to do an animation for specific time interval. Then when i reached the limit (ex. 5x blink by $().fadeOut().fadeIn()), I want to return a value.
This is the application:
function func_a(limit) {
var i = 0;
var defer = $.Deferred();
var x = setInterval(function () {
$('#output').append('A Running Function ' + i + '<br />');
if (i == limit) {
$('#output').append('A Done Function A:' + i + '<br /><br />');
clearInterval(x);
defer.resolve('B');
}
i++;
}, 500);
return defer;
}
function func_b(limit) {
var c = 0;
var defer = $.Deferred();
var y = setInterval(function () {
$('#output').append('B Running Function ' + c + '<br />');
if (c == limit) {
$('#output').append('B Done Function B:' + c + '<br /><br />');
clearInterval(y);
defer.resolve('A');
}
c++;
}, 500);
return defer;
}
func_a(3).then( func_b(5) ).then( func_a(2) );
This is not functioning well, it should print A,A,A,Done A,B,B,B,B,B,Done B,A,A,Done A but here it is scrambled and seems the defer runs all function not one after the other but simultaneously. That's why I asked this question because I want to return return defer; inside my if...
if (i == limit) {
$('#output').append('A Done Function A:' + i + '<br /><br />');
clearInterval(x);
defer.resolve('B');
// planning to put return here instead below but this is not working
return defer;
}
Do you expect it to wait until the interval ends? That would be a real pain for the runtime, you would block the whole page. Lots of thing in JS are asynchronous these days so you have to use callback, promise or something like that:
function git(limit, callback) {
var i = 0;
var git = setInterval(function () {
console.log(i);
if (i === limit - 1) {
clearInterval(git);
callback('done');
}
i++;
}, 800);
}
git(5, function (x) {
console.log(x);
});
Using a promise it would look like this:
function git(limit, callback) {
var i = 0;
return new Promise(function (resolve) {
var git = setInterval(function () {
console.log(i);
if (i === limit - 1) {
clearInterval(git);
resolve('done');
}
i++;
}, 800);
});
}
git(5)
.then(function (x) {
console.log(x);
return new Promise(function (resolve) {
setTimeout(function () { resolve("hello"); }, 1000);
});
})
.then(function (y) {
console.log(y); // "hello" after 1000 milliseconds
});
Edit: Added pseudo-example for promise creation
Edit 2: Using two promises
Edit 3: Fix promise.resolve
Try to get a callback to your git function.
function git(limit,callback) {
var i = 0;
var git = setInterval(function () {
console.log(i);
if (i === limit - 1) {
clearInterval(git);
callback('done') // now call the callback function with 'done'
}
i++;
}, 800);
}
var x = git(5,console.log); // you passed the function you want to execute in second paramenter

Execute a function BEFORE ANY function is executed

What I want to do is to execute a function automatically every time BEFORE ANY function is executed in JS, regardless if it's a custom or native function if possible.
ie.
whatIWant(functionName){
return console.log('called before '+functionName);
}
function blah(){
return console.log('called blah');
}
function meh(){
return console.log('called meh');
}
alert('woot');
blah();
//will output :
//called before blah
//called blah
meh();
//will output :
//called before meh
//called meh
alert();
//will output :
//called before alert
//will pop up dialog: woot
I do not want to do the following:
Function.prototype.onBefore = function(){};
blah.onBefore();
is it even possible to do what I am asking for? any suggestions, read, or w/e?
Thanks in advance.
What about just providing your function as a callback to whatIWant like this:
function whatIWant(fn) {
var fnName = fn.toString();
fnName = fnName.substr('function '.length);
fnName = fnName.substr(0, fnName.indexOf('('));
console.log('called before ' + fnName);
fn();
}
function meh() {
console.log('called meh');
}
function blah() {
console.log('called blah');
}
whatIWant(meh);
whatIWant(blah);
whatIWant(alert)
what do you guys think about this solution? :)
function bleh(){
console.log('exe a');
}
function limitFn(fn,n) {
var limit = n ;
var counter = 1 ;
var fnName = fn.toString();
fnName = fnName.substr('function '.length);
fnName = fnName.substr(0, fnName.indexOf('('));
return function(){
if(counter <= limit) {
console.log(counter + ' call before ' + fnName + ' limit ' + limit);
counter++;
fn();
} else {
console.log('limit of ' + limit + ' exes reached') ;
}
};
}
limited = limitFn(bleh,2);
limited();
limited();
limited();
limited();

Categories