Object scoping rules seem to change due to seemingly irrelevant library? - javascript

So, I'm familiar with the general gist of JavaScript's features regarding objects. They're refcounted and if they go to zero, they die. Additionally, apple = banana where both are objects doesn't copy banana to apple but makes apple a reference to banana.
That being said, some of my code has something like this:
// imagine ws require() and setup here...
var RateLimit = require("ws-rate-limit")('10s', 80);
SickWebsocketServer.on("connection", function(mysocket, req){
// blahblahblah...
RateLimit(mysocket); // See below...
mysocket.on("limited", function(){console.log("someone was limited!"});
mysocket.on("message", function(data){
if(JSON.parse(msg).MyFlagToMessageASpecificWebsocketClient){ // obvs dont do this lol
findme = MyArr.find(guy=>guy.Socket==mysocket);
if(findme) console.log("TRIGGER PLS :)"); // GOAL
else console.log("DON'T TRIGGER"); // SOMETHING WENT WRONG
}
});
MyArr.push({MyName:"my SICK object", MyNumber:MyArr.length, Socket:mysocket})
}
The library used for rate limiting is called ws-rate-limit and I have pasted a shortened (non-code removed) version down below (since it's tiny). Imagine it to be in a package called ws-rate-limit (because it is :D).
const duration = require('css-duration')
module.exports = rateLimit
function rateLimit (rate, max) {
const clients = []
// Create an interval that resets message counts
setInterval(() => {
let i = clients.length
while (i--) clients[i].messageCount = 0
}, duration(rate))
// Apply limiting to client:
return function limit (client) {
client.messageCount = 0
client.on('newListener', function (name, listener) {
if (name !== 'message' || listener._rated) return
// Rate limiting wrapper over listener:
function ratedListener (data, flags) {
if (client.messageCount++ < max) listener(data, flags)
else client.emit('limited', data, flags)
}
ratedListener._rated = true
client.on('message', ratedListener)
// Unset user's listener:
process.nextTick(() => client.removeListener('message', listener))
})
// Push on clients array, and add handler to remove from array:
clients.push(client)
client.on('close', () => clients.splice(clients.indexOf(client), 1))
}
}
My issue is that, when I do use the RateLimit function, the "DON'T TRIGGER" code triggers. If I literally remove that one single line (RateLimit(mysocket)) it goes into "TRIGGER PLS :)".
The above is obviously logically simplified from my actual application but I think you get the gist. Apologies for any misspellings that may lead to undefineds or stuff like that; I promise you my code works if not for the RateLimit(mysocket) line.
When I add console.logs into the find function to log both the guy.Socket object and the mysocket object, with the RateLimit(mysocket) line, the mysocket object's .toString() returns [object global] rather than [object Object]. I know that this is some complicated JavaScript object scoping problem, but I have no clue where to start in terms of investigating it.
Thank you! :)

I'll take a random shot in the dark based on intuition. My best guess is that your issue is with the guy.Socket==mysocket line. Comparing objects that way will only check if they both point to the same heap memory location, even if it's two different stack variables. In your example I can only assume that the RateLimit(mysocket) line is somehow creating a new heap location for that stack variable (creating a new object from it) and because of that your == comparison is then no longer equal (even if they have the exact same values) because they're pointing to different locations.
Try using: JSON.stringify(guy.socket) === JSON.stringify(mysocket).

Related

Nodejs genetic algorithm memory management?

I'm trying to implement a genetic algorithm and have the problem of heap memory getting too large. To the extend that it throws an error.
I'm afraid it has something to do with my population array. I displayed the memory usage while running the program and recognized it is growing and growing and never gets freed up.
Consider the following setup:
let used = {}
class Trainer {
static breed = function(elite) {
//code for making a new generation
return brood
}
constructor() {
this.population = []
}
async evolve(data, options, callback) {
// potential point where the error may be
// because I see the memory growing and never getting smaller
// but I think it should get smaller because I don't
// reference the old generation any more or do I ?
while (error >= threshold) {
// train each member of the population async
// and than make a new population out of the elite
const elite = this.population.slice(0, 10)
this.population = Trainer.breed(elite) <--- ¯\_(ツ)_/¯
callback(info)
used = process.memoryUsage()
}
}
}
const trainer = new Trainer
const data = getData()
const options = makeOptions()
function log(info) {
console.log(info)
console.log(used)
}
async function test() {
await trainer.evolve(data, options, log)
}
test()
Now I have some questions.
Is it true that on each generation the old array is not referenced anymore and get's garbage collected and makes some free space in memory?
How can I analyze the memory usage by each function to get better inside of where the problem may is in my code?
Because the code is very large I tried to simplified my problem. But if you are interested in the complete code please have a look in my repo:
https://github.com/kiro7shiro/image-generator
You can find the described setup from above in the "/cli/image-generator-evolve.js" file.

Reference changed before change of reference

What I am trying to do is to switch out an object's property (a string) with a matching (keyed) object from another object where the values are keyed.
So for example...
const dataRefs = {
'idkey1': { title: "Key1", /*...etc... */ },
'idkey2': { title: "Key2", /*...etc... */ },
'idkey3': { title: "Key3", /*...etc... */ },
// ...etc...
};
const pages = [
{ title: "A Page", data: 'idkey1' },
// ...etc...
];
Using the below code I want to switch out pages[n].data with the matching property in dataRefs. So using a forEach on the pages...
pages.forEach(page => page.data = dataRefs[page.data])
Doing this results in page.data property becoming undefined, even though it should match.
If I try to debug by outputting it to console, I get some unusual effect of seeing the undefined only when the code is added after the output....
// This works and does the match exactly as I want it.
pages.forEach(page => console.log("%s: ", page.data, dataRefs[page.data]));
// Output:
// idkey1: undefined
// This however results in bizzare behaviour and ends up with "undefined".
pages.forEach(page => {
// using console.log to see what's going on...
console.log("%s: ", page.data, dataRefs[page.data]);
page.data = dataRefs[page.data];
});
// Output:
// [Object object]: undefined
// Trying this alternative, just in case how the DOM inspector
// might be using references, but still the same issue...
pages.forEach(page => {
console.log(page.data + ": ", dataRefs[page.data]);
page.data = dataRefs[page.data];
});
// Output:
// [Object object]: undefined
Have checked spelling of variables and gone over and over the code trying so many variants but it seems that no matter what I do, calling page.data = dataRefs[page.data] does not work. Would this be some sort of complex race-condition or have I been watching too much Matrix of late?
This is being called in the Component's render() method.
Using Safari 14.1.2, if that helps.
The issue was related with Next.JS. Best guess is that Next.JS was pre-rendering the data, storing it in some JSON cache file and passing that to the component render function....or something like that.
Using the browser's inspector, a breakpoint at the problematic line page.data = dataRefs[page.data] was only ever triggered once, and showed the data had already been manipulated by the function, before it had been called. Which is simply odd. Removing the line, the breakpoint would trigger and the data not converted.
This leads me to believe it to be some sort of NextJS pre-lifecycle thing, possibly as part of the SSG process.
To resolve the issue and move on, I used a check if (page.data instanceof Object) return; to stop it from running twice, which seemed to do the trick. Not ideal, but without a better reason, this will have to suffice. So the code ultimately went like....
pages.forEach(page => {
// skip the loop if the data has already been converted
// could have also used a string check, but both should work for now.
if (page.data instanceof Object) return;
// now change the data if it's still a string referrence
page.data = dataRefs[page.data]));
});
Again, appologies that I don't have the best answer, but this was the only way to resolve it, and since Javascript does not do this normally (have done this sort of thing so many times without issue), it will have to be chalked up to a NextJS/SSG (or some other processor) issue.
Would love to get any NextJS expert's knowledge on how this could happen.

How to fix "Function returned undefined, expected Promise or value" error when function loops

I have an android application I developed, that allows the sign up of users. I wrote a firebase cloud function that triggers when a User is created, to generate a 5-digit random integer value for the user who just signed up and it stores the generated code in firebase real time database in the following structure.
MainProject
|
|-Codes
|-UniqueUID_1
|-code:72834
|-UniqueUID_2
|-code:23784
The function that I deployed in order to make sure that the code generation is in the backend, is as seen below. There is a value "checker" which is initialised as 0. I use this value to determine when to exit the while loop. Basically I want the function to generate a 5-digit random value, then check the real time database if that generated value exists in all entries under "Codes", then if it does not exist, append it to the Codes under the relevant UID. If it exists, checker remains zero and the loop continues.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
var checker = 0;
exports.createUserCode = functions.auth.user().onCreate(event => {
while (checker == 0){
var newRand = getUserCode(89999,10000);
var userObject = {
uCode : newRand
};
//run a db query to strategically check value generated
return admin.database().ref("Codes/").orderByChild("uCode").equalTo(newRand).once("value",snapshot => {
if (!snapshot.exists()){
checker = 1;
//add uCode into respective uid slot under Codes
console.log(""+newRand+" : "+event.uid);
return admin.database().ref('Codes/' + event.uid).set(userObject);
}else{
checker = 0;
console.log("uCode "+newRand+" exists");
console.log("uCode generation failed for: "+event.uid);
}
});
}
});
function getUserCode(size, add){
return Math.floor(Math.random()*size+add);
}
I tested it and it worked fine. I thought the problem was solved. However, on the 7th to 11th trial, it gave me a Function returned undefined, expected Promise or value error. I tried it again after a while, and it generated the code fine. Some one else tested it and it brought the same error.
How can I fix this issue to ensure it always works? Thanks in advance.
It's really not clear to me what this function is supposed to do, and the top-level while loop doesn't make sense to me. However, I can see there are a few things wrong with what this code is doing.
First of all, it's depending on the global state checker too heavily. This value will not be the consistent for all function invocations, because they all won't be running on the same server instance. Each running server instance will see a different value of checker. Please watch this video series for more information about how Cloud Functions runs code.
Second of all, when checker has a value of 1 when the function starts, the function will do exactly what the error message says - it will return undefined. It should be pretty easy to see how this happens by reading the code.
To fix this, I suggest first coming up with a clear description of what this function is supposed to do when invoked. Also, I would strongly suggest eliminating dependency on global variables, unless you are absolutely certain you understand what you're doing and the effect they have.
I had the same problem a while ago. ESLint won't allow the function to complete because it evaluates whether every part of your code returns a promise.
From what i can see the first part of the if does return something. Try returning a boolean in the else block.
if (!snapshot.exists()){
checker = 1;
//add uCode into respective uid slot under Codes
console.log(""+newRand+" : "+event.uid);
return admin.database().ref('Codes/' + event.uid).set(userObject);
}else{
checker = 0;
console.log("uCode "+newRand+" exists");
console.log("uCode generation failed for: "+event.uid);
return false;
}

Check if string is in list in javascript not working (in hyperledger)

So, i wanted to check if an ad was displayed on an allowed website using javascript. I used a methodology explained in that post Determine if string is in list in JavaScript.
Here is my code :
async function ImpCertification(tx) {
Impression = await getAssetRegistry('org.example.basic.Impression')
const source = Impression.PrintedSite
whitelist = ["Youtube", "Google", "Facebook", "Twitter"]
if (whitelist.indexOf(source) < 0) {
// Checks if source in whitelist
throw new Error ('This impression does not respect branding')
}
// Checks every necessary conditions to validate impression
if (whitelist.indexOf(source) >=0) {
// Save the old value of the asset.
const oldValue = Impression.Valid;
// Update the asset with the new value.
Impression.Valid = true;
// Get the asset registry for the asset.
const assetRegistry = await getAssetRegistry('org.example.basic.transaction.ValidateImpression');
// Update the asset in the asset registry.
await assetRegistry.update(Impression);
// Emit an event for the modified asset.
let event = getFactory().newEvent('org.example.basic', 'Validation');
event.asset = tx.asset;
event.oldValue = oldValue;
event.newValue = true;
emit(event);
}
await null
}
I'm developing an hyperledger business network so some parts maybe seem exotic but I must bring your attention to the whitelist/indexOf stuff. It just doesn't work although I get the logic of it.
I tried to enter every element of the whitelist in Impression.PrintedSite but it keeps throwing the "this impression does not respect branding" error everytime, wether it is right or not.
Before you ask, I checked for caps in Impression.PrintedSite, it is a string, I tried the other method suggested using booleans and "includes" but it just won't work. Halp !
At first, make sure that the string that you pass to indexOf is an actual string:
typeof <your-string-variable> === 'string'
To check if a string is in your list I suggest using ES6 Array.prototype.includes() :
['a', 'b', 'c'].includes('b')
To check if a string is a substring of the strings in your list combine Array.prototype.includes() method with String.prototype.includes() method:
(I also used ES6 reduce there to simplify the expression)
['hello', 'world', 'my', 'name', 'is', 'johny', 'cash'].reduce((current, item) => current || item.includes('substring_to_search'), false);
So long story short, since the ID of the object "impression" wasn't filled in the function the constant was just empty because fetching information that didn't exist.
Therefore since null is not in whitelist the indexof returned -1 and every time the program would enter this condition and return the error.
This simple fix is
async function ImpCertification(ValidateImpression) {
imp = ValidateImpression.impression
const source = imp.PrintedSite
ect...
}
where "ValidateImpression" is the transaction which points to the Impression asset through an ID
asset Impression identified by ImpID {
o String ImpID
o String PrintedSite
}
transaction ValidateImpression {
--> Impression impression
}

How to make Screeps find sources?

In Screeps, I this code doesn't work:
var sources = creep.room.find(Game.FIND_SOURCES_ACTIVE);
It says this:
Cannot read property 'find' of undefined
I have been looking around and cannot find ANY other way to find sources.
Also I've noticed that most of other peoples code doesn't work and even the tutorial's code no longer works when put into the real game.
I can't be completely sure about your issue since I don't have your complete code to go off of but one issue could be that creepis not defined.
You need somewhere in your code to define creep such as a for loop to loop over each of your creeps in the game or room.
var roleMiner = require('role.miner') // role.miner being the module name for miner actions
for(var name in Game.creeps) {
var creep = Game.creeps[name];
//
// do whatever you wish with the current selected creep.
//
// most of the time you will call a module similar to what the tutorials suggest and put your actions for it in there
//
if(creep.memory.role == 'miner'){
roleMiner.run(creep); // passes the current selected creep to the run function in the module
}
}
So, in your roleMiner module you would have something that defines your miners actions.
var roleMiner = {
run: function(creep) {
// this one returns an array of the sources that are in the room with the creep
var sourcesRoom = creep.room.find(FIND_SOURCES);
// this one returns the source object which is closest to the creeps positon
var sourcesClose = creep.pos.findClosestByRange(FIND_SOURCES);
}
}
module.exports = roleMiner;
Hope this helps.
Screeps have some ... mechanism when sharing your data between each game tick.
If you store any thing in global Memory object, your data will lose all its prototype.
to restore your prototype use Object.setPrototypeOf(creep,Creep.prototype) or create new Creep object from your creep id.
I think what you are looking for is:
var sources = creep.pos.findClosestByRange(Game.SOURCES);
or
var sources = creep.pos.findClosestByPath(Game.SOURCES);
im a new player, not sure my code is efficient, i think the find method will be like this:
var sources = creep.room.find(FIND_SOURCES_ACTIVE)
creep will going to the active resource to harvester.

Categories