How can I profile cache hits with lodash memoize? - javascript

I have memoized lodash function that takes an object as its argument. When this function gets called, how can I tell how often its hitting the cache vs evaluating the function with new arguments?

If you're just doing it in development, you can do something like count the number of times cache.get is called vs how many times the function is called. Something like
var calls = 0;
var hits = 0;
function test(b) {
calls += 1;
return b + 1;
}
var mem_test = _.memoize(test);
mem_test.cache.get = function(n) {
var cached = mem_test.cache.get;
calls += 1;
hits += 1;
return function() {
var result = cached.call(this, n);
return result;
}
}
mem_test(1);
mem_test(2);
mem_test(2);
console.log(calls);
console.log(hits);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
That simple example should output 3 and 1.

Related

How should I fix this asynchronicity problem in my "Josephus Problem" code?

Background
I'm new to JavaScript and am solving various formulations of the Josephus Problem to better understand the syntax. Using a circularLinkedList implementation*, I've solved the classic formulation: Wikipedia||Numberphile. I've also solved the problem for any fixed number of fighters and a fixed number of skips between eliminations (e.g., if skipping two fighters between eliminations, 1 eliminates 4, 5 eliminates 8, etc). I am now trying to solve the problem given any function that indicates the number of skips at a given moment.
Problem
I can't access the return value of my skip function. I understand from 1, 2, 3 that my issue involves asynchronicity, but am having trouble isolating takeaways from the long responses involving AJAX and jQuery, which I'm unfamiliar with. Could I get an ELI5 solution? I apologize for my lack of understanding.
Code
function winnerStepFunc(num, func) {
let cll = new circularLinkedList(); //Initializing list with participants
for (let a = 0; a < num; a++) {
cll.append(a);
}
function next(funcSteps) { //Generating string indicating #steps from function's output
let toEvaluate = "start";
for (let i = 0; i < funcSteps; i++) {
toEvaluate += ".next"
}
return toEvaluate;
}
let start = cll.getHead(); //Selecting first eliminator
while (cll.size() > 1) {
let toCheck = func(); // PROBLEM LINE
console.log("toCheck = " + toCheck); //toCheck = undefined
let str = next(toCheck);
while (eval(str) !== start && cll.size() > 1) { //
let locCurrent = cll.indexOf(start.element);
start = eval(str).next;
cll.removeAt(((locCurrent + toCheck)% cll.size()));
}
cll.delete(eval(str).next.element);
start = start.next;
}
console.log(start.element + 1);
}
function callFunction(name, args) { // builds function string to be evaluated
let result = name + "(";
for (let i = 0; i < args.length -1; i++) {
result += args[i] + ", ";
}
result += args[args.length-1] + ")";
return result;
}
function callFunction(name) {
let result = `${name}()`;
return result;
}
function addOne() { //<--The first basic example I'm trying:
return ++globalTimes; //Make the step increase by one for each elimination
}
var globalTimes = 0;
winnerStepFunc(12, function(){eval(callFunction("addOne"))});
*CLL Implementation
You don't return in your function. I would remove all the eval stuff and just call the function directly.
winnerStepFunc(12, addOne);

In angular updating one variable inexplicably updates another

I am using angular and plotly to plot either the raw data or a moving average. I have the moving average working but I am running into an issue with assigning variables. I retrieve an array of user objects which each have an x and y key with arrays associated with them.
$scope.init=function(){
$rootScope.page='companyResults';
$scope.isPlotlyDone = false;
$scope.moving = false;
var refresh = function () {
incidentService.dayWiseTripsByUser(...).then(function (plotArray){
$scope.unaffectedPlot = plotArray;
$scope.movingAveragePlot = allMoving(plotArray);
console.log($scope.unaffectedPlot[0].y);
console.log($scope.movingAveragePlot[0].y);
});
};
refresh();
}
Im that code block, I would expect that $scope.unaffectedPlot[0].y and $scope.movingAveragePlot[0].y would have different arrays since I ran the latter through the following set of functions. The curious thing is that both $scope variables are synced, so if I run the second through allMoving the unaffectedPlot variable also gets smoothed and neither get synced obviously if I don't call allMoving. What am I missing about Angular? What is a good way to have a moving average work with a toggle? My plan is to show one variable or the other depending on if a button is clicked.
var d3_numeric = function(x) {
return !isNaN(x);
}
var d3sum = function(array, f) {
var s = 0,
n = array.length,
a,
i = -1;
if (arguments.length === 1) {
// zero and null are equivalent
while (++i < n) if (d3_numeric(a = +array[i])) s += a;
} else {
while (++i < n) if (d3_numeric(a = +f.call(array, array[i], i))) s += a;
}
return s;
};
var movingWindowAvg = function (arr, step) {
return arr.map(function (_, idx) {
var wnd = arr.slice(idx - step, idx + step + 1);
var result = d3sum(wnd) / wnd.length; if (isNaN(result)) { result = _; }
return result;
});
};
var allMoving = function(pltArray) {
var movingArray = [];
pltArray.forEach(function(plot){
var oneMoving = plot;
oneMoving.y = movingWindowAvg(plot.y, 5);
movingArray.push(oneMoving);
});
return movingArray;
}
This actually isn't an angular issue. I had to test it some since I didn't see what was going on either.
When you wrote
oneMoving.y = blah
you were actually altering the contents of plot for each element and in turn altering the contents of plotArray unintentionally (since plot is an object)
So you are only creating a reference variable when you say 'var onMoving = plot' )
To outright solve your problem you can clone plot but that isn't so clean of a process
One easy yet dirty way is
JSON.parse(JSON.stringify(obj))
from this thread
I threw together a shotty example that captures what was going wrong for you
var array = [{one:1, two:2},{one:1, two:2},{one:1, two:2}],
copyArray = array,
newArr = doStuff(array)
function doStuff(a) {
var otherNewArr = []
a.forEach(function(ae) {
var aVar = ae
aVar.one = 5
otherNewArr.push(aVar)
})
return otherNewArr
}
console.log(copyArray,newArr)
And to fix it just replace
var aVar = ae
with
var aVar = JSON.parse(JSON.stringify(ae))

Error in my closure

JS Bin example
Why does it not count, my output is always 1 in the console. I am new to closures and I must be missing something simple? Here is the code from the jsbin:
var counterFunc = function()
{
var count = 0;
var incCount = function()
{
count = count + 1;
return count;
};
return incCount();
};
var myCounter = counterFunc;
console.log(myCounter());
console.log(myCounter());
By returning incCount() - the result of the invocation - from your counterFunc, you're not really creating a closure function. You want to return a function, and invoke the counterFunc() to create it:
var counterFunc = function() {
var count = 0;
var incCount = function() {
count = count + 1;
return count;
};
return incCount ;
// ^
};
var myCounter = counterFunc();
// ^^
console.log(myCounter());
console.log(myCounter());
You should be returning the inner function itself, not the result of calling it
You therefore need to replace return incCount() with:
return incCount;
You subsequently need to directly invoke counterFunc() when you declare myCounter:
var myCounter = counterFunc(); // myCounter is now the closure
Only then will myCounter be assigned a reference to the inner function, that happens to hold a "closure" over the local variable count.

Does JavaScript cache/optimize code if repeated multiple times?

I'm currently writing a small framework to test the speed of JavaScript functions. When I repeatedly call the same methods with the same parameter, it gives me strange results:
Function Execution Time
isEvenBitwise 38.00000000046566
isEvenModulo 38.00000000046566
isEvenPointless 38.00000000046566
Here are my functions:
var myFunctions =
{
isEvenBitwise: function(number)
{
return !(number & 1);
},
isEvenModulo: function(number)
{
return (number % 2 == 0);
},
isEvenPointless: function(number)
{
return 1;
}
}
The code that runs the functions:
PerformanceTest.prototype.measureTime = function()
{
for (var indexTests = 0; indexTests < this.testCount; indexTests++)
{
var results = [];
for (var currentFunction in this.functions) {
var contextFunction = this.functions[currentFunction];
var startTime = performance.now();
for (var i = 0; i < this.iterationsPerTest; i++)
{
var heh = contextFunction.apply(this, arguments)
}
var executionTime = performance.now() - startTime;
var result = {};
result.testName = currentFunction;
result.executionTime = executionTime;
results.push(result);
}
this.testResults.push(results);
}
}
Does the JavaScript interpreter cache/optimize my code? If so, how does it work? Or is there anything else happening I'm not aware of?
Edit: This seems to occur only in chrome, firefox works just fine with these results:
Function Execution Time
isEvenBitwise 9.652258097220447
isEvenModulo 37.546061799704376
isEvenPointless 8.512472488871936
After looking at your code I am going to make a guess that Chrome is being smart about what you are doing. It is seeing this:
var startTime = performance.now();
for (var i = 0; i < this.iterationsPerTest; i++)
{
var heh = contextFunction.apply(this, arguments)
}
var executionTime = performance.now() - startTime;
It is correctly assessing that the contextFunction has no side effects, recognising that the heh variable exists only within the loop scope and is never used and then optimising the entire loop away because it doesn't do anything.

setTimeout inside for loop [duplicate]

This question already has answers here:
setTimeout in for-loop does not print consecutive values [duplicate]
(10 answers)
Closed 7 years ago.
I want a string to appear character-for-character with the following code:
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
for(c = 0; c < text.length; c++)
{
setTimeout('textScroller.innerHTML += text[c]', 1000);
}
}
window.onload = initText;
It's not working.. what am I doing wrong?
Try something like this:
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
var c = 0;
var interval = setInterval(function() {
textScroller.innerHTML += text[c];
c++;
if(c >= text.length) clearInterval(interval);
}, 1000);
}
Note I added clearInterval to stop it when it's needed.
Currently, you are defining 18 timeouts and all will be executed ~ at once.
Second problem is, you pass instructions to execute as a String. In that case, the code won't have access to all variables defined in initText, because evaluated code will be executed in global scope.
IMO, this should do the job
function initText(){
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
var c = 0;
(function(){
textScroller.innerHTML += text.charAt(c++);
if(text.length > c){
setTimeout(arguments.callee, 1000);
}
})();
}
Even more generic than answer by #yauhen-yakimovich:
Using Timeout:
var repeat = (function () {
return function repeat(cbWhileNotTrue, period) {
/// <summary>Continuously repeats callback after a period has passed, until the callback triggers a stop by returning true. Note each repetition only fires after the callback has completed. Identifier returned is an object, prematurely stop like `timer = repeat(...); clearTimeout(timer.t);`</summary>
var timer = {}, fn = function () {
if (true === cbWhileNotTrue()) {
return clearTimeout(timer.t); // no more repeat
}
timer.t = setTimeout(fn, period || 1000);
};
fn(); // engage
return timer; // and expose stopper object
};
})();
Using Interval:
var loop = (function () {
return function loop(cbWhileNotTrue, period) {
/// <summary>Continuously performs a callback once every period, until the callback triggers a stop by returning true. Note that regardless of how long the callback takes, it will be triggered once per period.</summary>
var timer = setInterval(function () {
if (true === cbWhileNotTrue()) clearInterval(timer);
}, period || 1000);
return timer; // expose stopper
};
})();
Slight difference between the two indicated in comments -- the repeat method only repeats after the callback performs, so if you have a "slow" callback it won't run every delay ms, but repeats after every delay between executions, whereas the loop method will fire the callback every delay ms. To prematurely stop, repeat uses an object as the returned identifier, so use clearTimeout(timer.t) instead.
Usage:
Just like answer by #soufiane-hassou:
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
var c = 0;
var interval = repeat/* or loop */(function() {
textScroller.innerHTML += text[c];
c++;
return (c >= text.length);
}, 1000);
As mentioned, premature stopping would be:
/* if repeat */ clearTimeout(interval.t);
/* if loop */ clearInterval(interval);
Try this:
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
for(c = 0; c < text.length; c++)
{
setTimeout("textScroller.innerHTML += '" + text[c] + "'", 1000 + c*200);
}
}
window.onload = initText;
Try using a closure:
function init() {
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
var c = 0;
function run() {
textScroller.innerHTML += text[c++];
if (c<text.length)
setTimeout(run, 1000);
}
setTimeout(run, 1000);
}
init()
The problem in your code is that the code you put in the string will run in the global context, where textScroller is not defined (it is defined inside your function).
I want to share a snippet (based on answer by Soufiane Hassou). It extends to the case when you literally replace a for-loop body to be iterated over some array in a fixed interval of time. Basically same synchronous loop but with "sleep" pausing (because javascript is not a synchronous programming language).
function loop(arr, take, period) {
period = period || 1000;
var i = 0;
var interval = setInterval(function() {
take(i, arr[i]);
if (++i >= arr.length) { clearInterval(interval);}
}, period);
}
Usage example:
loop([1, 2, 3, 4], function(index, elem){
console.log('arr[' + index + ']: ' + elem);
});
Tested in Node JS. Hope that helps someone.
edit>
the following update makes code usable together with libs doing heavy "prototyping" (like jQuery or prototype):
function loop(arr, take, period) {
period = period || 1000;
var scope = {
i: 0,
arr: arr,
take: take,
};
var iterate = (function iterate() {
if (this.i >= this.arr.length) { clearInterval(this.interval); return}
take(this.i, this.arr[this.i++]);
}).bind(scope);
scope.interval = setInterval(iterate, period);
}
Your for loop is setting a timeout for every character at once, so they will not appear in sequence, but all at once. Your setTimeout should include code to another setTimeout that will include the next character to display.
So something like this (didn't test this)
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
setTimeout('nextChar(text)', 1000);
}
function nextChar(text){
if(text.length > 0){
textScroller.innerHTML += text[0];
setTimeout('nextChar(text.substring(1))', 1000);
}
}
If you want to preserve setTimeOut (instead of setInterval) and use named function (instead of evaluating code block in setTimeOut call), then this could be helpful:
var b = {
textScroller: document.getElementById('textScroller'),
text: "Hello how are you?"
};
function initText() {
for(c = 0; c < b.text.length; c++) {
setTimeout("append("+c+")", 1000 + c*200);
}
}
function append(c) {
b.textScroller.innerHTML += b.text[c];
}
window.onload = initText;
With the above you can pass a parameter to append function.
To pass several parameters the next code does the trick:
var glo = [];
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = "Hello how are you?";
var timeout_time;
for(c = 0; c < text.length; c++) {
glo[glo.length] = {text:text, c:c, textScroller:textScroller};
timeout_time = 1000 + c * 200;
setTimeout("append(" + (glo.length - 1) + ")", timeout_time);
}
}
function append(i)
{
var obj = glo[i];
obj.textScroller.innerHTML += obj.text[obj.c];
obj = null;
glo[i] = null;
}
window.onload = initText;
With the above you have only one global array glo. In loop you create new array members to glo and in append() function refer to these members using index which is passed as parameter.
CAUTION: the second code sample is not meant as best or most suitable solution to OP:s problem, but may benefit in other setTimeOut relative problems, eg. when someone wants to make a presentation or performance test where some functionalities are needed to call after some delay. The advantage of this code is to make use of for loops (many coders want to use for loops) and the possibility to use also inner loops and the ability to "send" local variables in their loop time state to timeOut functions.
May be better to loop in cascade. For exemple to fade a div :
div=document.createElement('div');
div.style.opacity=1;
setTimeout(function(){fade(1);},3000);
function fade(op){
op-=.05;
if(op>0) setTimeout(function(){div.style.opacity=op;fade(op);},30);
else document.body.removeChild(div);
}

Categories

Resources