Solving inaccesible variable inside jquery .bind() anonymous function using react lifecycle - javascript

I need to have access to the jqconsole variable outside of the anonymously bound function. How do i instantiate it outside of the JQuery habitat? If possible, i would just save it globally or to my state. I did not manage to get it to run this way.
componentDidMount = () => {
// Execute after fully loaded
$(window).bind('load', () => {
const jqconsole = $('#console').jqconsole(
'Welcome to the console!\n',
'>'
);
// register some workarounds
jqconsole.RegisterMatching('{', '}', 'brace');
jqconsole.RegisterMatching('(', ')', 'paran');
jqconsole.RegisterMatching('[', ']', 'bracket');
const startPrompt = () => {
// scroll to bottom -- NOT WORKING YET
$('#console').scrollTop($('#console')[0].scrollHeight);
// Start the prompt with history enabled.
jqconsole.Prompt(true, input => {
let transformedString;
// Manage Output
try {
transformedString = window.eval(input);
if (typeof transformedString === 'object') {
this.writeToConsole(jqconsole, 'object', transformedString);
} else {
this.writeToConsole(jqconsole, 'message', transformedString);
}
// Restart the input prompt.
startPrompt();
} catch (error) {
this.writeToConsole(jqconsole, 'error', error);
// Restart the input prompt.
startPrompt();
}
});
};
// Restart the input prompt.
startPrompt();
});
};
To be precise: I have this class method writeToConsole, and want to call it without having to deliver the instance of jqconsole:
// Manage Output
writeToConsole = (jqconsole, type, message) => {
console.log('writing to console # console');
if (type === 'error') {
jqconsole.Write(message + '\n', 'jqconsole-output-error');
} else if (type === 'message') {
jqconsole.Write(message + '\n', 'jqconsole-output');
} else if (type === 'object') {
jqconsole.Write(JSON.stringify(message) + '\n', 'jqconsole-output');
} else {
console.log('error # writeToConsole');
return null;
}
};
Thank you for your time and help.

I solved my own question, by instantiating my jqconsole to this.myConsole in the constructor. This way it is accessible throughout the whole component.

Related

GC won't collect function in setTimeout

I have done several tests and read a lot about Garbage Collection in Javascript applications but there must be something I'm not getting right.
I have a react app that polls data from a JSON file using fetch every 25 seconds. The function I'm calling is mapped to the props using redux in the App.js. I'm calling the function like this on componentDidMount
this.fetchDisplayContent(1000);
This is the function's definition which is also located in the App.js
fetchDisplayContent = (fetchInterval = 500, repeat = true) => {
clearTimeout(this._contentInterval);
this._contentInterval = setTimeout(() => {
if (this._mode === "preview") {
this.props.fetchContent(config.WEB_SERVER + '/display/fetchDisplayContents?mode=prvw&localLastUpdate=0&display=' + this._displayId, 0, this._webkey);
}
else if (this._mode === "web") { //live web version
this.props.fetchContent(config.WEB_SERVER + '/display/fetchDisplayContents?mode=web&localLastUpdate=0&display=' + this._displayId, 0, this._webkey);
}
else if (this._mode === "module") {
this.props.fetchModuleContent(config.WEB_SERVER + '/display/fetchModuleContents?mode=prvw&module=' + this._module + '&project=' + this._project + '&module_id=' + this._module_id, this._webkey);
}
else { //form offline file
if (typeof config.DISPLAY === "number") {
this.props.fetchContent(this._baseURL + '/data/displayContents.json', 0, this._mode);
} else {
this.props.fetchContent(this._baseURL + '/data/display_' + this._displayId + '_contents/displayContents.json', 0, this._mode);
}
}
if (repeat) {
this.fetchDisplayContent();
}
}, fetchInterval);
}
And this is the action:
export function fetchContent(url, lastUpdated, webkey) {
return (dispatch) => {
let now = new Date();
let rev = now.getTime()/1000;
if (url.includes('?')){
url+="&rev="+rev
}
else{
url+="?rev="+rev
}
if (webkey){
url+="&webkey="+webkey
}
fetch(url)
.then((response) => {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
})
.then((response) => response.json())
.then((content) => {
if (Number(content.last_update)>Number(lastUpdated)){
dispatch(contentFetchSuccess(content))
}
else{
return null;
}
}).catch(() => {
dispatch(contentHasErrored(true));
});
};
}
fetchInterval is originally 25000 but I changed it to 500 for testing purposes and reproduce the issue faster.
Here's you can see that references to the handler provided to the setTimeout are not been cleaned out by the GC and the heap keeps growing over time. Eventually the app freezes after a few days and I suspect this is the reason. I confirmed that the number of listeners doesn't increment in the profile as well as the heap's size when the setTimeout is not running.
Performance Profile
What would be the proper way to call this function in a setTimeout without leaking memory?

How to find the calling test in cypress custom command

I have a command that overwrites pause to add the input from a dialog to the reports. I want to know if there is a way to know what test is calling the function so that I can customize the message on the inputs.
Cypress.Commands.overwrite('pause', (originalFn, element, options) => {
var tryThis = '';
if (//place calling the function == file1) {
tryThis = 'message1';
} else if (//place calling the function == file2) {
...
} else if (//place calling the function == file3) {
...
}
var datalog = window.prompt(tryThis, "Log your results");
cy.addContext("DATALOG:" + datalog);
return originalFn(element, options)
})
As well as access via the Mocha properties there is also
For the spec file Cypress.spec
Properties for my.spec.js
Cypress.spec.absolute: "C:/.../my.spec.js"
Cypress.spec.name: "my.spec.js"
Cypress.spec.relative: "cypress\integration\my.spec.js"
Cypress.spec.specFilter: "my"
Cypress.spec.specType: "integration"
For the test cy.state('runnable')
For
describe('my-context', () => {
it('my-test', () => {
Properties and methods,
const title = cy.state('runnable').title; // "my-test"
const fullTitle = cy.state('runnable').fullTitle(); // "my-context my-test"
const titlePath = cy.state('runnable').titlePath(); // ["my-context", "my-test"]
You can also add metadata to the test
describe('my-context', () => {
it('my-test', { message: "my-message" }, () => {
and grab it in the command overwrite
const message = cy.state('runnable').cfg.message; // "my-message"
I tried this and it worked for me (my version of cypress is 6.1.0):
cy.log(Cypress.mocha.getRunner().suite.ctx.test.title);
More info: https://github.com/cypress-io/cypress/issues/2972

Return upon another file check

So I'm trying to run a few checks inside a file. Lets say inside checks.js I have
module.exports = async (content) => {
// Check no.1
if (content.id != 'SomeID') return;
// Check no.2
if (content.length > 20) return;
//..etc
}
And in my main file I am requiring this file. I want it to return in the original file depending on the outcome of checks.js So lets say the content id isn't the same as 'SomeID', I want it to return and not to continue the rest of the code in my main file. I did require('filePath')(content) But it doesn't actually return in the main file as it should by instructions in checks.js What am I doing wrong and what should I be doing. Thank you in advance!
checks.js is returning an AsyncFunction, you must await it.
checks.js:
module.exports = async (content) => {
// Check no.1
if (content.id != 'SomeID') return;
// Check no.2
if (content.length > 20) return;
//..etc
return true // maybe your not returning truthy?
}
index.js:
const checks = require('./checks');
(async () => {
console.log('typeof checks()', typeof checks);
console.log('instance of', checks.constructor.name);
//
let content = {
id: 'SomeID'
};
if (await checks(content)) {
console.log('1. passed');
} else {
console.log('1. failed');
}
//
content = {
id: 'WrongID'
};
if (await checks(content)) {
console.log('2. passed');
} else {
console.log('2. failed');
}
})();
Will output when run:
typeof checks() function
instance of AsyncFunction
1. passed
2. failed

See Understanding async/await on NodeJS for more details.

looping the callback function in node js

This is a piece of code which writes data to a ble device and reads data from it. data is written to the device in the form of a buffer. the value in 'mydata' (AAAD0000) is the command to be written in order to read the data.
function named chara3() consists of write and read function which is a callback function in which the command is passed read back.
My requirement is the 'mydata' value which i said earlier, the last two zeros is the memory address. i need to read the data in different memory addresses starting from zero to 59. That is AAAD0000 to AAAD0059. so of course i need to run a loop. If I'm reading the zeroth location, the code is quite fine and i got the output as well but when i tried to make it inside a loop, the code is all a mess. the read part is not executing.
can any one suggest a better way to read data from zeroth memory location to 59th memory location (AAAD0000 to AAAD0059)???
first command writes to it
then reads data
memory location incremented by 1
this should repeat up to 59
var mydata = 'AAAD0000';
function chara3() {
var buff2 = new Buffer(mydata, 'hex');
SensorCharacteristic.write(buff2, false, function(error) { //[0x002d]
console.log('Writing command SUCCESSFUL',mydata);
if (!error) {
SensorCharacteristic.read((error, data) => {
console.log("i just entered");
if (data.toString('hex') != '0000') {
console.log('Temperature History: ', data.toString('hex'));
enter();
}
else {
console.log('contains null value');
} //else
});
}
function enter()
{
mydata = (parseInt(mydata, 16) + 00000001).toString(16);
}
}); //.write
} //chara3
there's no error. But some part of the code is not executing.
You can use the recursion by wrapping your methods into a promise
async function chara3(mydata = 'AAAD0000') {
if (mydata === 'AAAD0059') {
return;
}
var buff2 = new Buffer(mydata, 'hex');
return new Promise((resolve) => {
SensorCharacteristic.write(buff2, false, function (error) { //[0x002d]
console.log('Writing command SUCCESSFUL', mydata);
if (!error) {
SensorCharacteristic.read(async (error, data) => {
console.log("i just entered");
if (data.toString('hex') != '0000') {
console.log('Temperature History: ', data.toString('hex'));
let next = await chara3(enter())
return resolve(next);
}
else {
console.log('contains null value');
return resolve();
} //else
});
}
}); //.write
});
} //chara3
function enter() {
return (parseInt(mydata, 16) + 00000001).toString(16);
}
Also if you can convert your methods SensorCharacteristic.write and SensorCharacteristic.read into promises you can simply map
function chara3(mydata) {
var buff2 = new Buffer(mydata, 'hex');
await SensorCharacteristic.write(buff2, false);
console.log('Writing command SUCCESSFUL', mydata);
let data = await SensorCharacteristic.read();
if (data.toString('hex') != '0000') {
console.log('Temperature History: ', data.toString('hex'));
enter();
} else {
console.log('contains null value');
}
};
let promiseArray = Array(60).fill().map((_, i) => (parseInt('AAAD0000', 16) + i).toString(16)).map(chara3);
Promise.all(promiseArray).then(() => console.log('done'));

Unreliable behaviour in Node.js

I have a Node.js application that, upon initialisation, reads two tables from an SQL database and reconstructs their relationship in memory. They're used for synchronously looking up data that changes (very) infrequently.
Problem: Sometimes I can't access the data, even though the application reports successfully loading it.
Code:
constants.js
module.exports = {
ready: function () { return false; }
};
var log = sysLog('core', 'constants')
, Geo = require('../models/geo.js');
var _ready = false
, _countries = []
, _carriers = [];
function reload() {
_ready = false;
var index = Object.create(null);
return Geo.Country.find().map(function (country) {
var obj = country.toPlainObject()
, id = obj.id;
delete obj.id;
index[id] = obj;
return Object.freeze(obj);
}).then(function (countries) {
log.debug('Loaded ' + countries.length + ' countries');
_countries = countries;
return Geo.Carrier.Descriptor.find().map(function (carrier) {
var obj = carrier.toPlainObject();
if (obj.country) {
obj.country = index[obj.country];
}
return Object.freeze(obj);
}).then(function (carriers) {
log.debug('Loaded ' + carriers.length + ' carriers');
_carriers = carriers;
});
}).finally(function () {
_ready = true;
});
}
reload().catch(function (err) {
log.crit({ message: 'Could not load constants', reason: err });
process.exit(-42);
}).done();
module.exports = {
reload : reload,
ready : function () { return _ready; },
countries : function () { return _countries; },
carriers : function () { return _carriers; }
};
utils.js
var log = sysLog('core', 'utils')
, constants = require('./constants');
module.exports = {
getCountryByISO: function(iso) {
if (!iso) {
return;
}
if ('string' != typeof iso) {
throw new Error('getCountryByISO requires a string');
}
if (!constants.ready()) {
throw new UnavailableError('Try again in a few seconds');
}
switch (iso.length) {
case 2:
return _.findWhere(constants.countries(), { 'iso2' : iso.toUpperCase() });
case 3:
return _.findWhere(constants.countries(), { 'iso3' : iso.toUpperCase() });
default:
throw new Error('getCountryByISO requires a 2 or 3 letter ISO code');
}
},
getCarrierByCode: function(code) {
if (!code) {
return;
}
if ('string' != typeof code) {
throw new Error('getCarrierByCode requires a string');
}
if (!constants.ready()) {
throw new UnavailableError('Try again in a few seconds');
}
return _.findWhere(constants.carriers(), { 'code' : code });
},
getCarrierByHandle: function(handle) {
if (!handle) {
return;
}
if ('string' != typeof handle) {
throw new Error('getCarrierByHandle requires a string');
}
if (!constants.ready()) {
throw new UnavailableError('Try again in a few seconds');
}
return _.findWhere(constants.carriers(), { 'handle' : handle });
}
};
Use case
if (data.handle) {
carrier = utils.getCarrierByHandle(data.handle);
if (_.isEmpty(carrier)) {
throw new InternalError('Unknown carrier', { handle: data.handle });
}
}
What's going on: All errors are logged; as soon as I see an error (i.e. "Unknown carrier") in the logs, I check the SQL database to see if it should've been recognised. That has always been the case so far, so I check the debug log to see if data was loaded. I always see "Loaded X countries" and "Loaded Y carriers" with correct values and no sign of "Could not load constants" or any other kind of trouble.
This happens around 10% of the time I start the application and the problem persists (i.e. didn't seem to go away after 12+ hours) and seems to occur regardless of input, leading me to think that the data isn't referenced correctly.
Questions:
Is there something wrong in constants.js or am I doing something very obviously wrong? I've tried setting it up for cyclical loading (even though I am not aware of that happening in this case).
Why can't I (sometimes) access my data?
What can I do to figure out what's wrong?
Is there any way I can work around this? Is there anything else I could to achieve the desired behaviour? Hard-coding the data in constants.js is excluded.
Additional information:
constants.reload() is never actually called from outside of constants.js.
constants.js is required only in utils.js.
utils.js is required in app.js (application entry); all files required before it do not require it.
SQL access is done through an in-house library built on top of knex.js and bluebird; so far it's been very stable.
Versions:
Node.js v0.10.33
underscore 1.7.0
bluebird 2.3.11
knex 0.6.22
}).finally(function () {
_ready = true;
});
Code in a finally will always get called, regardless of if an error was thrown up the promise chain. Additionally, your reload().catch(/* ... */) clause will never be reached, because finally swallows the error.
Geo.Country.find() or Geo.Carrier.Descriptor.find() could throw an error, and _ready would still be set to true, and the problem of your countries and carriers not being set would persist.
This problem would not have occurred if you had designed your system without a ready call, as I described in my previous post. Hopefully this informs you that the issue here is really beyond finally swallowing a catch. The real issue is relying on side-effects; the modification of free variables results in brittle systems, especially when asynchrony is involved. I highly recommend against it.
Try this
var log = sysLog('core', 'constants');
var Geo = require('../models/geo.js');
var index;
var _countries;
var _carriers;
function reload() {
index = Object.create(null);
_countries = Geo.Country.find().map(function (country) {
var obj = country.toPlainObject();
var id = obj.id;
delete obj.id;
index[id] = obj;
return Object.freeze(obj);
});
_carriers = _countries.then(function(countries) {
return Geo.Carrier.Descriptor.find().map(function (carrier) {
var obj = carrier.toPlainObject();
if (obj.country) {
obj.country = index[obj.country];
}
return Object.freeze(obj);
});
});
return _carriers;
}
reload().done();
module.exports = {
reload : reload,
countries : function () { return _countries; },
carriers : function () { return _carriers; }
};
constants.reload() is never actually called from outside of
constants.js.
That's your issue. constants.reload() reads from a database, which is an aysnchronous process. Node's require() is a synchronous process. At the time constants.js is required in utils.js and the module.exports value is returned, your database query is still running. And at whatever point in time that app.js reaches the point where it calls a method from the utils module, that query could still be running, resulting in the error.
You could say that requiring utils.js has the side-effect of requiring constants.js, which has the side-effect of executing a database query, which has the side-effect of concurrently modifying the free variables _countries and _carriers.
Initialize _countries and _carriers as unresolved promises. Have reload() resolve them. Make the utils.js api async.
promises.js:
// ...
var Promise = require('bluebird');
var countriesResolve
, carriersResolve;
var _ready = false
, _countries = new Promise(function (resolve) {
countriesResolve = resolve;
})
, _carriers = new Promise(function (resolve) {
carriersResolve = resolve;
});
function reload() {
_ready = false;
var index = Object.create(null);
return Geo.Country.find().map(function (country) {
// ...
}).then(function (countries) {
log.debug('Loaded ' + countries.length + ' countries');
countriesResolve(countries);
return Geo.Carrier.Descriptor.find().map(function (carrier) {
// ...
}).then(function (carriers) {
log.debug('Loaded ' + carriers.length + ' carriers');
carriersResolve(carriers);
});
}).finally(function () {
_ready = true;
});
}
reload().catch(function (err) {
log.crit({ message: 'Could not load constants', reason: err });
process.exit(-42);
}).done();
module.exports = {
reload : reload,
ready : function () { return _ready; },
countries : function () { return _countries; },
carriers : function () { return _carriers; }
};
utils.js
getCarrierByHandle: function(handle) {
// ...
return constants.carriers().then(function (carriers) {
return _.findWhere(carriers, { 'handle' : handle });
});
}
Use case:
utils.getCarrierByHandle(data.handle).then(function (carrier) {
if (_.isEmpty(carrier)) {
throw new InternalError('Unknown carrier', { handle: data.handle });
}
}).then(function () {
// ... next step in application logic
});
This design will also eliminate the need for a ready method.
Alternatively, you could call constants.reload() on initialization and hang all possibly-dependent operations until it completes. This approach would also obsolete the ready method.
What can I do to figure out what's wrong?
You could have analyzed your logs and observed that "Loaded X countries" and "Loaded Y carriers" were sometimes written after "Unknown carrier", helping you realize that the success of utils.getCarrierByHandle() was a race condition.

Categories