Incomprehensible work decorator function - javascript

Is a function:
var f = function(a) { console.log(a) };
function throttle(func, ms) {
var stop = false, savedThis, savedArgs;
return function wrapper() {
if(stop) {
savedArgs = arguments;
savedThis = this;
return;
}
func.apply(this, arguments)
stop = true;
setTimeout(function() {
stop = false;
if(savedArgs) {
wrapper.apply(savedThis, savedArgs);
savedArgs = savedThis = null;
}
}, ms);
};
}
// brake function to once every 1000 ms
var f1000 = throttle(f, 1000);
f1000(1); // print 1
f1000(2); // (brakes, less than 1000ms)
f1000(3); // (brakes, less than 1000ms)
The first call f1000 (1) displays 1. f1000 (2), the second call does not work, but it will keep in savedAggs link to the arguments of the second call. The third launch also does not work, but it will overwrite the link to the arguments of the third call. Through 1000 ms setTimeout cause an anonymous function, the variable will stop within the meaning of the false. Condition of work, and the wrapper will be called recursively. But then I can not understand what's going on? When this code works: savedArgs = savedThis = null;?

The function is a bit incomprehensible, yes. Its job is to throttle the rate of invocations to at most one per 1000 ms - however if they occur more frequent, it will also repeat the last invocation as soon as the timeout has finished.
It might better be written
function throttle(func, ms) {
var stop = false, savedThis, savedArgs;
function invoke() {
stop = true; // the last invocation will have been less than `ms` ago
func.apply(savedThis, savedArgs);
savedThis = savedArgs = null;
setTimeout(function() {
stop = false; // the timeout is over, start accepting new invocations
if (savedArgs) // there has been at least one invocation during
// the current timeout
invoke(); // let's repeat that
}, ms);
}
return function wrapper() {
savedArgs = arguments;
savedThis = this;
if (stop)
return;
else
invoke();
};
}

Related

Call a function max once in a sec

I have a function that is used to send messages and that is called multiple times in a sec.
But I want to call that function once a sec and delay other calls of that function with another 1-second of the previous call.
So that only that function run in the background and called once in a second, no matters how many times it is called it will delay each call to one second ahead.
For example:
function foo(a) {
console.log(a)
}
foo('one');
foo('two');
foo('three');
in the above example, foo is called three times within a sec but I want to have it called like after the 1 second it should return "one" after 2 seconds it should return 'second' and so on and it should be asynchronous.
How can I do this?
The technology I am using is Javascript.
Thanks
Well this is the first thing I came up with - perhaps it's crude.
var queuedUpCalls = [];
var currentlyProcessingCall = false;
function foo(a) {
if (currentlyProcessingCall) {
queuedUpCalls.push(a);
return;
}
currentlyProcessingCall = true;
setTimeout(function(){
console.log(a);
currentlyProcessingCall = false;
if (queuedUpCalls.length) {
var nextCallArg = queuedUpCalls.shift();
foo(nextCallArg);
}
},1000);
}
foo('one');
foo('two');
foo('three');
For each call, if you're not currently processing a call, just call setTimeout with a delay of 1000ms. If you are processing a call, save off the argument, and when the setTimeout that you kicked off finishes, process it.
Somewhat improved answer using setInterval:
var queuedUpCalls = [];
var timerId;
function foo(a) {
queuedUpCalls.push(a);
if (timerId) {
return;
}
timerId = setInterval(function(){
if (!queuedUpCalls.length) {
clearInterval(timerId);
timerId = null;
return;
}
var nextCallArg = queuedUpCalls.shift();
console.log(nextCallArg);
}, 1000);
}
foo('one');
foo('two');
foo('three');
Here is a simple queue system, it basically just pushes the functions onto an array, and then splice's them off every second.
const queue = [];
setInterval(function () {
if (!queue.length) return;
const f = queue[0];
queue.splice(0, 1);
f();
}, 1000);
function foo(a) {
queue.push(function () {
console.log(a)
});
}
foo('one');
foo('two');
foo('three');
you could use this to run the main code first and then run some more code a little later.
function firstfunction() {
alert('I am ran first');
setTimeout(function(){ alert('I am ran 3 seconds later') }, 3000);
}
<button onclick="firstfunction();">click me</button>
function foo(a)
{
if (typeof foo.last == 'undefined')
foo.last = Date.now();
var now = Date.now();
if (now - 1000 > foo.time)
foo.last = now;
setTimeout(function()
{
console.log(a);
}, (foo.last += 1000) - now);
}
This will queue each console.log call with intervals of 1 second, the first call will also be delayed by 1 second.
You could do this:
function foo() {
console.log(“ran”);
}
setInterval(foo, 1000);
In the last line, writing foo() without parenthesis is intentional. The line doesn’t work if you add parentheses.

How to get last value from throttled function

The documentation for the _.throttle function states that:
Creates a throttled function that only invokes func at most once per
every wait milliseconds. The throttled function comes with a cancel
method to cancel delayed func invocations and a flush method to
immediately invoke them. Provide an options object to indicate whether
func should be invoked on the leading and/or trailing edge of the wait
timeout. The func is invoked with the last arguments provided to the
throttled function. Subsequent calls to the throttled function return
the result of the last func invocation
I'm interested in this line:
Subsequent calls to the throttled function return
the result of the last func invocation
I've tried:
var throttled = _.throttle(updateModelData, 1000);
service.on('change', function () {
throttled(5);
});
function updateModelData(data) {
// all calls here log 5's
console.log(data);
return data;
}
setTimeout(function() {
throttled(); // here updateModelData is executed with `undefined` value
}, 5000);
The problem is that throttled() triggers function without returning the data. How can I invoke it so that it returns last data?
EDIT:
According to source code, the value will be returned only if no pending function call exists isCalled === false:
function debounced() {
args = arguments;
stamp = now();
thisArg = this;
trailingCall = trailing && (timeoutId || !leading);
if (maxWait === false) {
var leadingCall = leading && !timeoutId;
} else {
if (!maxTimeoutId && !leading) {
lastCalled = stamp;
}
var remaining = maxWait - (stamp - lastCalled),
isCalled = remaining <= 0 || remaining > maxWait;
!!!!! HERE
if (isCalled) {
if (maxTimeoutId) {
maxTimeoutId = clearTimeout(maxTimeoutId);
}
lastCalled = stamp;
result = func.apply(thisArg, args);
}
else if (!maxTimeoutId) {
maxTimeoutId = setTimeout(maxDelayed, remaining);
}
}
...
return result;
}
So the following will work:
var throttled = _.throttle(updateModelData, 10000);
service.on('change', function () {
throttled(5);
});
function updateModelData(data) {
// all calls here log 5's
console.log(data);
return data;
}
setTimeout(function() {
throttled(); // returns 5
}, 15000);
The issue is that, when you have leading invocations (the default behavior for _.throttle), when you first call the throttled function (or first call it after after your delay time has passed) it immediately calls the underlying function, before returning anything.
That means that the "result of the last function invocation" might be the result of a function invocation that was caused by your current call to the throttled function. So your call to throttle() calls updateModelData() and then returns undefined, since updateModelData() returns undefined.
Here's some sample code that might clarify this:
var foo = (x) => x;
var leading = _.throttle(foo, DELAY, {leading: true, trailing: false}); //these are the default options for leading and trailing
var trailing = _.throttle(foo, DELAY, {leading: false, trailing: true});
leading(1); //Calls foo(1), returns 1
leading(2); //Doesn't call foo, returns 1,
leading(3); //Doesn't call foo, returns 1
trailing(1); //Doesn't call foo, returns undefined
trailing(2); //Doesn't call foo, returns undefined
//DELAY ms later
//foo(2) is called, due to the most recent call to bar2
leading(); //Calls foo(), returns undefined
leading(1); //Still returns undefined from above
trailing(); //Doesn't call foo, returns 2
trailing(1); //Doesn't call foo, returns 2
//Another DELAY ms later
leading("Whatever"); //Calls foo("Whatever"), returns "Whatever";
Here's a version of your JSFiddle that makes it slightly more obvious too.
Really, you shouldn't call a function just to get the last value returned by it, so I'd suggest you just manage the last value yourself and not rely on _.throttle to do it for you. For example:
var lastResultOfFoo;
var foo = function (x) {
lastResultOfFoo = x;
return x;
}
//OR (if you don't mind attaching arbitrary properties to functions)
var foo = function (x) {
foo.lastResult = x;
return x;
}
The following code works fine:
var throttled = _.throttle(updateModelData, 1000);
var i = 0;
function updateModelData(data) {
return data;
}
var interval = setInterval(function() {
console.log(throttled(i++));
if (i === 6) {
clearInterval(interval);
console.log('Last value: ' + throttled());
}
}, 2000);
Output:
0
1
2
3
4
5
"Last value: 5"
DEMO

closures - why is this line coded like this?

I am looking at the Leaflet api.
Is there a reason why in setTimeout, it is calling wrapperFn.apply(context, args); and not fn.apply(context, args); ?
I tried it out, and it gives me the same output. But wondering if there a significance to it ?
function a(fn, time, context) {
var lock, execOnUnlock;
return function wrapperFn() {
var args = arguments;
if (lock) {
execOnUnlock = true;
return;
}
lock = true;
setTimeout(function () {
lock = false;
if (execOnUnlock) {
wrapperFn.apply(context, args);
execOnUnlock = false;
}
}, time);
fn.apply(context, args);
};
},
The function creates a wrapper for the function that is the first parameter, which can only be executed at an interval specified by the second parameter. If you call it again one or more times inside the interval, the last of those calls will be executed automatically after the interval.
var f = a(someFunction, 1000, {});
f(1); // this will execute the function
f(2); // this will not be executed
f(3); // this will be executed after a second
setTimeout(function(){
f(4); // this will be executed a half second later (two seconds after the first)
}, 1500);
The call that is made automatically at the end of the interval will lock the function for another time interval. If the code would call fn instead of wrapperFn, then that call would not be locked, and you could call the function again inside the interval. Example:
var f = a(someFunction, 1000, {});
f(1); // this will execute the function
f(2); // this will not be executed
f(3); // this will be executed after a second
setTimeout(function(){
f(4); // this would be executed immediately (1.5 seconds after the first)
}, 1500);

How can I rate limit how fast a javascript function allows itself to be called?

I have a JavaScript function which actually ends up making a server-side call. I want to limit the rate at which this function can be called.
What is an easy way I can limit how fast my javascript function will get called by say 200-500 milliseconds or so? Should I use a javascript timer control?
Libraries like bottleneck and node-rate-limiter pretty much cover all use cases.
If your problem involves too much work being created, use a queue:
const work_queue = [];
function queue(message) {
work_queue.push(message)
}
function run() {
const work = work_queue.shift();
if (work !== undefined) {
scan_one(work);
}
}
setInterval(run, 15);
If you problem involves a function being called too often:
let last = +new Date();
function run() {
const now = +new Date();
if (now - last > 5000) { // 5 seconds
last = now;
run_once();
}
}
First you need to establish if you want to rate limit in that you disregard all function calls that are made during the period when you are waiting, or whether you want to simply queue up requests so that you ensure you never make more than X requests per second.
If you want the former solution (disregard new functional calls), then you should look at http://documentcloud.github.com/underscore/#throttle
If you want to rate limit so that you never call your function more than X times per second, but don't lose those function calls altogether, then you need a wholly different solution.
I have written an underscore extension at https://gist.github.com/1084831
You can see a working example at http://jsbin.com/upadif/8/edit#preview
This will not allow the function to run if less than 500 milliseconds have passed since the last call.
(function(window, undefined){
var canCall = true;
window.funcName = function(){
if (!canCall)
return;
//Your function
canCall = false;
setTimeout(function(){
canCall = true;
}, 500);
}
})(window);
You can create a flag that is raised when the function is called and start a timer and if this flag is raised then you can not call the function, then after a certain time, the timer is called and he turns off the flag, allowing you to call the function again.
The flag can be anything, like a bool or something.
It kind of depends what functionality you want. Here is a link to a page that has 2 great functions: https://remysharp.com/2010/07/21/throttling-function-calls
throttle: process first call, then throttle next calls based on a threshhold (first and last call will be processed, but only a couple calls in between)
debounce: don't process any calls until function hasn't been called for a delay (only 1 will be called after a call and quite period)
It depends on what you want to do with subsequent calls, where you wanna run it etc.
Wait on subsequent calls: throttle-wait
Discard subsequent calls lodash.throttle sugar.throttle...
More advance like throttle on multiple server or more configs
bottleneck
Also serverside throttler like ratelimiter (async-ratelimiter), node-rate-limiter
You can also use the SugarJS function "throttle":
http://sugarjs.com/api/Function/throttle
I would suggest Pat Migliaccio solution found here
function limiter(fn, wait){
let isCalled = false,
calls = [];
let caller = function(){
if (calls.length && !isCalled){
isCalled = true;
calls.shift().call();
setTimeout(function(){
isCalled = false;
caller();
}, wait);
}
};
return function(){
calls.push(fn.bind(this, ...arguments));
caller();
};
}
You can easily test it by creating a loop:
const logMessageLimited = limiter(msg => { console.log(msg); }, 1000);
for (let i = 0; i < 10; i++){
logMessageLimited(`[Message Log] Action (${i}) rate limited.`);
}
You can use debounce function
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this,
args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
var logging = debounce(function(){
alert("Heavy task");
}, 5000);
setTimeout(logging, 100);//callback executed after 5 seconds
More information on how debounce function works here http://qnimate.com/javascript-limit-function-call-rate/
try setinterval( "function()", 500)
fooCanBeCalled = true;
function foo(){
if(!fooCanBeCalled) return;
//Whatever you want to do
fooCanBeCalled = false;
setTimeout(function(){
{
fooCanBecalled = true;
}
, delayInMilliseconds);
}

Is there a way to check if a var is using setInterval()?

For instance, I am setting an interval like
timer = setInterval(fncName, 1000);
and if i go and do
clearInterval(timer);
it does clear the interval but is there a way to check that it cleared the interval? I've tried getting the value of it while it has an interval and when it doesn't but they both just seem to be numbers.
There is no direct way to do what you are looking for. Instead, you could set timer to false every time you call clearInterval:
// Start timer
var timer = setInterval(fncName, 1000);
// End timer
clearInterval(timer);
timer = false;
Now, timer will either be false or have a value at a given time, so you can simply check with
if (timer)
...
If you want to encapsulate this in a class:
function Interval(fn, time) {
var timer = false;
this.start = function () {
if (!this.isRunning())
timer = setInterval(fn, time);
};
this.stop = function () {
clearInterval(timer);
timer = false;
};
this.isRunning = function () {
return timer !== false;
};
}
var i = new Interval(fncName, 1000);
i.start();
if (i.isRunning())
// ...
i.stop();
The return values from setTimeout and setInterval are completely opaque values. You can't derive any meaning from them; the only use for them is to pass back to clearTimeout and clearInterval.
There is no function to test whether a value corresponds to an active timeout/interval, sorry! If you wanted a timer whose status you could check, you'd have to create your own wrapper functions that remembered what the set/clear state was.
I did this like below, My problem was solved. you should set the value like "false", when you clearTimeout the timer.
var timeer=false;
----
----
if(timeer==false)
{
starttimer();
}
-----
-----
function starttimer()
{
timeer_main=setInterval(activefunction, 1000);
timeer=true;
}
function pausetimer()
{
clearTimeout(timeer_main);
timeer=false;
}
Well you can do
var interval = setInterval(function() {}, 1000);
interval = clearInterval(interval);
if (typeof interval === 'undefined'){
...
}
but what are you actually trying to do? clearInterval function is an always success function and it will always return undefined even if you call it with a NaN value, no error checking in there.
You COULD override the setInterval method and add the capability to keep track of your intervals. Here is an untestet example to outline the idea. It will work on the current window only (if you have multiple, you could change this with the help of the prototype object) and this will only work if you override the functions BEFORE any functions that you care of keeping track about are registered:
var oldSetInterval = window.setInterval;
var oldClearInterval = window.clearInterval;
window.setInterval = function(func, time)
{
var id = oldSetInterval(func, time);
window.intervals.push(id);
return id;
}
window.intervals = [];
window.clearInterval = function(id)
{
for(int i = 0; i < window.setInterval.intervals; ++i)
if (window.setInterval.intervals[i] == id)
{
window.setInterval.intervals.splice(i, 1);
}
oldClearInterval(id);
}
window.isIntervalRegistered(id)
{
for(int i = 0; i < window.setInterval.intervals; ++i)
if (window.setInterval.intervals[i] == func)
return true;
return false;
}
var i = 0;
var refreshLoop = setInterval(function(){
i++;
}, 250);
if (isIntervalRegistered(refrshLoop)) alert('still registered');
else alert('not registered');
clearInterval(refreshLoop);
if (isIntervalRegistered(refrshLoop)) alert('still registered');
else alert('not registered');
The solution to this problem: Create a global counter that is incremented within your code performed by setInterval. Then before you recall setInterval, test if the counter is STILL incrementing. If so, your setInterval is still active. If not, you're good to go.

Categories