I cannot use Obfuscator.io to uglify my JS script because it contains a setTimeout within a function that calls itself.
MCVE:
function repeater() {
// DO SOME STUFF...
setTimeout(repeater, 100);
}
repeater();
Custom obfuscation settings required to reproduce:
- Identifier Names Generator: Mangled
- Reserved Names: $ - jQuery
Obfuscator.io's error message:
Error: #postConstruct error in class t: #postConstruct error in class t: Maximum call stack size exceeded
I've read a few other Stack Overflow questions about this. I understand that calling setTimeout(func) inside func is not actually recursion.
But still, Obfuscator.io's algorithm can't handle a self-invoking setTimeout delay.
How do I make a repeatedly-executing function using setTimeout without calling it in the function itself? I don't want to use setInterval because I want the delay to begin each time after the function's code has run. setInterval ignores that.
I think your issue is actually in the use of
Reserved Names: $ - jQuery
as using that as the configuration results in this
Which is what you're getting, if you change it to ^$ which is what the text box and description on the website says it should be, your code obfuscates fine
Reserved Names
Disables obfuscation and generation of identifiers, which being matched by passed RegExp patterns.
For instance, if you add ^someName, the obfuscator will ensure that all variables, function names and function arguments that starts with someName will not get mangled.
I this you have something like that:
function repeater() {
// DO SOME STUFF...
const someCodeInJQuery = $('#someId')
setTimeout(repeater, 100);
}
repeater();
Just need change to:
function repeater() {
// DO SOME STUFF...
const someCodeInJQuery = jQuery('#someId'); // Pay attention here
setTimeout(repeater, 100);
}
repeater();
Anwer: change $ to jQuery in your code, because obfuscator have
reserved words
Reccomendation: the best way - use uglifyJS instead of obfuscator
Related
I was writing some code for a widget in "Scriptable" that shows random word at a certain time. The widget calls itself with a timeout, on iPad. But it's exceeding the stack size. How do I solve this? I am using Javascript within "Scriptable" framework, so I don't have much freedom.
kanjiObj: Object; kanjiKeys: List; Timer().schedule(timeinterval, repeat, callback)
var randomNum = Math.floor(Math.random()*150)+1
var kanji = kanjiKeys[randomNum]
var kanjiMeaning = kanjiObj[kanjiKeys[randomNum]]
if(config.runsInWidget){
let widget = createWidget()
Script.setWidget(widget)
Script.complete()
function createWidget(){
let widget = new ListWidget()
widget.addText(kanji + "=>" + kanjiMeaning)
widget.wait = new Timer().schedule(1000*60*60, 150, createWidget())
In your case, you are calling the createWidget() function recursively by mistake. Your intention was different, you wanted to pass the function as a parameter to the schedule function, which accepts a function callback as the last parameter.
So you have to change to
widget.wait = new Timer().schedule(1000*60*60, 150, () => createWidget())
or
widget.wait = new Timer().schedule(1000*60*60, 150, createWidget)
But since this question is about "call stack size exceeded" people who have a different kind of this problem could stumble upon it, so I will answer in a general way below as well.
Programming is about recognizing patterns, so what you have in your code is a pattern (structure) of an infinite recursive call
function someFunction() {
// ... code before the recursive call that never returns from this function
// an unconditional call (or a conditional chain that is always true)
// of the function itself in the function scope instead of inside a callback/lambda
someFunction()
// ... could be more code, which does not matter,
// until the pattern above still holds true
}
So a structure (pattern) like this will result in an infinite recursive call, which eventually ends with a maximum call stack size exceeded. Call stack size is limited and an infinite recursive call eventually fills it up.
Javascript does not have built-in tail-recursion optimization (in practice, see compatibility), but in programming languages that do, if the function is tail-recursive, it would be optimized to a loop. In the case of an infinite tail-recursive function it would be optimized to an infinite loop, which would not fill the call stack, it would just loop forever (it would be working, but if not implemented correctly, it could make the application unresponsive).
So to resolve a problem like this in general, one has to break this pattern by breaking any (at least one) of the conditions above. This is the list:
code before the recursive call that never returns from this function
add a conditional return statement (also called a stop condition)
an unconditional call (or a conditional chain that is always true) to the function itself in the function scope instead of inside a callback/lambda
make the call conditional (make sure the condition chain can be false) or put it inside a callback/lambda. When you put it inside a
callback/lambda, then a different pattern applies (you have to check
the logic inside the call that will be calling the callback), but
calling the callback still has to be conditional, it has to have a
limit at some point.
after making a change, the code that is after the call, needs to be checked for the same pattern again, if the pattern is there again, break it in a similar way. Keep repeating this until the whole function does not form the pattern anymore - has stop condition(s) where needed.
In cases when you do need an infinite recursive call and the function is tail-recursive and your language does not support tail-recursion optimization, you would need to do the tail optimization yourself or use a library/framework that lets you do that.
If this does not solve your problem, have a look at the answers in this question that has collected a lot of reasons why a "maximum call stack size exceeded" might happen in Javascript.
This question already has answers here:
Accessing an object property with a dynamically-computed name
(19 answers)
Closed 1 year ago.
I'm working full-stack on a project, and I've run into a bit of a situation that I think I'll need to resolve fully so I can re-use it in future projects (fairly new to Node, but tons of programming languages and syntax under my belt), so a dirty fix might not be the best (eval()?) I have 3 files, here is an example of the logic:
// main.js
const call = require('./test.js');
config = require('config');
configObj = config.get('Site')
sites = Object.keys(configObj);
siteObj = config.get('Site' + "." + sites[0]); // This only calls Amazon, but in the real project it is a dynamic element
var callCommand = "call." + siteObj.functionCall + "(siteObj)"; // evaluates as call.amazon(siteObj)
setTimeout(() => {callCommand;}, 1500); // This does not work
setTimeout(() => {call.amazon(siteObj);}, 1500); /// This works
// default.json
{
"Site": {
"Amazon": {
"homePage": "https://www.amazon.com/",
"functionCall": "amazon"
}
}
// test.js
function amazon(siteObj) {
// some code
console.log("reached the function");
}
Basically, I'm going to be calling different functions from main.js, targeting the test.js. I need the function call to be dynamic, because it is based on the Site's callFunction key. For instance, once there are 10 sites, maybe it would call "call.xxxxxxx(siteObj)", instead. The string creating the call does not seem to be working, I think because it's a String and the line is looking for a function to execute. I get that, but again, I'm fairly new to Node/JS in general and I'm not exactly sure how to even word the question. I thought simply placing the proper text of the function call as a string would cause JS to execute that text, but I guess not.
Am I missing something simple? I know I will need dynamic function calls in the future of this project, and others, so while I can write logic in test.js or main.js to work around THIS example, writing separate function calls for each Site:
if (sites[0]) {call.amazon(siteObj);
if (sites[1]) {call.ebay(siteObj);
for instance, will get cumbersome, as the Sites list will only grow.
Therefore, we created the callFunction key to try and give each object it's exact call.
I'm not sure if it's parenthesis placement, or the way arrow functions work for the setTimeout, or what it is, but I've tried different instances of:
setTimeout(() => {call.$(siteObj.functionCall)(siteObj);}, 1500); // This does not work
setTimeout(() => {call.$(siteObj.functionCall)(siteObj))); }, 1500) // This does not work
I'm not sure how to use a regular variable, or an object's key properly in this instance to fetch "amazon", especially with the (siteObj) parameter.
and things like that. I am hoping more to be able to one-liner it like that SOMEHOW, but I don't know all of the tricks of this language yet.
I've also tried:
var callCommand = "call." + siteObj.functionCall + "(siteObj)"; // evaluates as call.amazon(siteObj)
var codeToExecute = callCommand;
var tmpFunc = new Function(codeToExecute);
setTimeout(() => {tmpFunc(); }, 1500);
With the above, I get "call" is not defined.
It works with the explicit text in there (call.amazon(siteObj)), but I need that "amazon" to be dynamic, preferably called from it's config key (even if I need to turn that key into a json formatted function).
I know this a huge wall of a read, but it is my first post here. Thanks in advance! Hopefully I formatted and named this post correctly without causing too much of a headache, I apologize if I did.
So, am I missing something simple? I feel like I am, but I'm not new to coding at all, and I am alone on this project (no other developers), and I'm trying to keep it good practice without too many, or any, dirty workarounds. Thank you!
setTimeout(() => {callCommand;}, 1500);
That evaluates the string and does nothing.
You can dynamically call the function from the exported object:
call[siteObj.functionCall](siteObj)
This way you access the object with the functions, that is the module exported, using the property that holds the function, and call it
const call = require('./test.js');
Is giving you something similar to
{
amazon: function() {}
}
Which is just an object
And as you want to dynamically access it, you have to use brackets instead of the dot notation, which allows you to access an object using a variable
I have this function in javascript.
function func_name(param_1, param_2)
{
//blah blah
}
Sometimes, I carelessly call it this way by supplying 1 parameter instead of 2.
func_name(aa);
However, javascript does not produce an error when the script is run. How can I make javascript produce an error or warning when the script is run? This will help one catch bugs more easily.
I am using node.js v6.
You could make use of the arguments object. Each function has an internal object called args, which is an array like object (has a length property) and contains the parameters which we use when we call the function.
function func_name(param_1, param_2){
if(arguments.length!==2){
// Here you can throw an error.
}
}
For further info, please have a look here.
I am using a jQuery plugin and running it through the Microsoft Ajax Minifier. My scripts work well for me, but now I am running into an issue with this plugin. The issue is that the plugin calls a function by its name using a string:
var s = (getCachedSortType(table.config.parsers, c) == "text") ? ((order == 0) ? "sortText" : "sortTextDesc") : ((order == 0) ? "sortNumeric" : "sortNumericDesc");
Note the "sortNumeric" and "sortNumericDesc". This calls these functions:
function sortNumeric(a, b) {
return a - b;
}
function sortNumericDesc(a, b) {
return b - a;
}
This is the only location these functions are called so the IDE VS2010 doesn't think that the functions are being called from anywhere... They are conditionally via the code above.
**Here is the Problem**
When this gets minified, the string name of the function stays, but the function gets removed because it does not thing its getting referenced.
Is there any way to adjust the settings minifier to not do this?
I have also seen it change the names of the functions so
function testFunctionName(a,b)
Would become
function a
This would also cause a problem for situations like mine...
Please note, that I know it is bad code design to hard code function names like this. Like I said it is a plug-in that I am using. I would accept a solution that would call the function out right instead of by string, but I am always hesitant to modify plug-ins.
From documentation:
-evals:(ignore|immediate|safeall) specifies how eval statements are to be treated. This is an important switch to be aware of. By default Ajax Minifier will ignore any eval statements, which can break your minified code if it contains eval statements that reference named local variables or functions. This is because by default Ajax Minifier will also rename local variables and function, but it doesn’t modify the text passed to the eval function, so those references may break. If you minify code and it stops working properly, check the code for eval statements. If there are any, try specifying one of the other two –evals switch options. The “immediate” options will not rename any variables or functions within the same scope as any eval call; the “safeall” option will not rename any variables or functions not only in the same scope as any eval call, but also in any parent scopes. This will seriously impair the minification of your code, but should ensure that any calls to the eval function will work as expected. The default setting is ignoreall.
Then try -evals:immediate and if your code is still broken you have to use -evals:safeall (even if this will make your JavaScript files bigger).
UPDATE
If you're not using eval then you have to skip function renaming at all:
-rename:(all|localization|none) specifies whether or not to automatically rename local variables and functions. Global variables and functions are not automatically renamed, nor are property names. If “localization” is specified, only variables that do not start with “L_” will be renamed. The default value is all.
Just add -rename:none.
Use -unused:keep switch to retain unused functions. This, naturally, will prevent minifier from removing really unused code.
Use -rename switch to assign permanent names to functions that you call by name.
The Javascript timer event has this basic syntax:
var t=setTimeout("javascript statement",milliseconds);
I have this function that gets called onkeyup() for some text box. I want the numeric_value_search() function to be called after a certain amount of time, which is 5 seconds in this example.
The key line is the 5th line. I have four different ways that it might be written, each of which gives the specified error:
timer=setTimeout(numeric_value_search(boundBox),5000);
ERROR: useless setTimeout call (missing quotes around argument?)
timer=setTimeout("numeric_value_search(boundBox)",5000);
ERROR: boundBox is not defined
timer=setTimeout("numeric_value_search("+boundBox+")",5000);
ERROR: missing ] after element list
timer=setTimeout(numeric_value_search("+boundBox),5000);
ERROR: data is passed nicely and there are no explicit errors but the timer doesn't work
var timer;
function chk_me(boundBox){
console.info(boundBox.id);
clearTimeout(timer);
// --- timer code here --- e.g. timer=setTimeout("numeric_value_search("+boundBox+")",5000);
}
As #kgiannakakis already said,
setTimeout(function() {
numeric_value_search(boundBox);
}, 5000);
is the way to go.
The reason is simple: When using a string argument it's like using eval() which is usually evil. When passing a function however you not only avoid putting code inside a string (which breaks syntax highlighting and might require escape orgies) but also have the possibility of using a closure to access variables in the current context without embedding them into a string (which might lead to code injection if not done properly).
Try this:
setTimeout(function() {
numeric_value_search(boundBox);
}, 5000);