I have an ajax code which causes memory leak (especially in IE).
function setStatus() {
var formInput=$(this).serialize();
$.getJSON('CheckStatus.action', formInput, function(data) {
if(data == false) {
function getEventsPeriodicaly() {
getEvents();
};
var timer = setInterval(function () {getEventsPeriodicaly();}, 5000);
}
}
);
}
function getEvents() {
var formInput=$(this).serialize();
$.getJSON('StartEP.action', formInput,function(data) {
var txt = $("#txtEventsArea");
if(data != null && data.toString().length!=0) {
txt.val(data.join('\n') + '\n' + txt.val());
data=null;
}
}
)}
StartEP
public String startEP() throws Exception {
logger.info("[EP] In startEP");
try {
synchronized(status) {
if(!getStatus()) {
EventProcessor amiep = EventProcessor.getInstance();
amiep.addObserver(this);
new Thread(amiep).start();
setStatus(true);
}
}
} catch (Exception ex) {
logger.error("Unable to start EP", ex);
return ERROR;
}
logger.info("[EP] In startEP, before loop");
while(!gotNewData) {
Thread.sleep(4000);
}
gotNewData = false;
logger.info("[EP] Out startEP");
return SUCCESS;
}
The StartEP action returns messages (about 5KB on each request). First I thought it concerned with setting text to textarea, but after some tests got that it is not the reason. Could it be setInterval method?
Is there any considerations?
thanks
I would say this looks pretty suspect:
while(!gotNewData) {
Thread.sleep(4000);
}
Where is gotNewData set? If you call the web service once and set gotNewData to true and then call another web service and set gotNewData to false I don't think there is a guarantee that you're setting the variable within the same instance of the application. Therefore, if you are not, then every time you're hitting the web service you are starting a new thread and then continually putting it back to sleep.
Related
I am trying to use a promise with a setInterval function to keep checking to see if a file exists(as it could be still generating on the backend) and then once it is available it runs the renderpage function as shown in my setupFunction(). Currently this program just keeps running until the setInterval maxes out and then it resolves even if the file is there.
async checkFileExist(path, timeout = 20000) {
let totalTime = 0;
let checkTime = timeout / 10;
var self = this;
return await new Promise((resolve, reject) => {
const timer = setInterval(function () {
totalTime += checkTime;
let fileExists = self.fileExist(path);
if (fileExists || totalTime >= timeout) {
alert(totalTime);
clearInterval(timer);
resolve(fileExists);
}
}, checkTime);
})
},
fileExist(urlToFile) {
var xhr = new XMLHttpRequest();
xhr.open('HEAD', urlToFile, false);
xhr.send();
if (xhr.status == "404") {
alert('false 404 ' + urlToFile)
return false;
} else {
alert('true file found ' + urlToFile)
return true;
}
},
setupFunction() {
var self = this
if (this.filedir == null || this.filedir == "") {
self.loadingFile = false
} else {
this.checkFileExist(this.filedir).then(function (response) {
self.loadingFile = false;
self.renderPage(this.pageNum);
}, function (error) {
console.error("Failed!", error);
})
}
}
},
mounted() {
this.setupFunction()
},
watch: {
filedir: function () { // watch it
this.setupFunction()
},
}
That won't tell you if a file exists. It will tell you if a URL finds a resource. It's an important distinction since a URL could be handled by server-side code and not a simple static file, while a file might exist and not have a URL.
Making an HTTP request is the simplest way to find out if a URL finds a resource. There are other ways to make HTTP requests (such as the fetch API), but they aren't faster, just different.
A potentially faster (but much more complicated) way would be to use a Websocket. You need to have it open before you wanted to know if the URL exists (otherwise any time savings are lost to establishing the Websocket connection) and you'd need to write the server side code which reacted to the Websocket message by working out if the desired URL existed and telling the client.
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.
I created my first app on Windows 8 vs 2012 and it runs and works fine. But when I try to say "helloworld" from JavaScript like this:
alert("Hello World");
I get an error:
Unhandled exception at line 21,
column 13 in ms-appx://1af489cf-bac6-419b-8542-fdc18bdd2747/default.html
0x800a1391 - JavaScript runtime error: 'alert' is undefined
What is the alternative if alert is obsolete?
You should use Windows.UI.Popups.MessageDialog:
(new Windows.UI.Popups.MessageDialog("Content", "Title")).showAsync().done();
However, you should be aware that:
This is not blocking like the familiar alert
Because it's not blocking you may try to show them multiple messages boxes; this isn't allow.
I answered another question like this here. Here's the code to allow you to call alert, and have multiple messages in flight:
(function () {
var alertsToShow = [];
var dialogVisible = false;
function showPendingAlerts() {
if (dialogVisible || !alertsToShow.length) {
return;
}
dialogVisible = true;
(new Windows.UI.Popups.MessageDialog(alertsToShow.shift())).showAsync().done(function () {
dialogVisible = false;
showPendingAlerts();
})
}
window.alert = function (message) {
if (window.console && window.console.log) {
window.console.log(message);
}
alertsToShow.push(message);
showPendingAlerts();
}
})();
Remember that alert is not a JavaScript function, it's a browser (host) function, therefore, it's not available in non browser environments.
This link tells you to do the following
Replace all alert functions with firing an event window.external.notify("message");
Use scriptnotify event in webview to get that message.
Show metro own dialog: MessageDialog
javascript:
(function () {
window.alert = function (message) {
window.external.notify( message);
}
//do some test
alert("a");
alert("b");
alert("c");
window.setInterval(function () {
alert("e");
alert("f");
}, 5000);
window.setInterval(function () {
alert("d");
alert("2");
}, 10000);
})();
C#:
//register ScriptNotify event
webView2.ScriptNotify += webView2_ScriptNotify;
async void webView2_ScriptNotify(object sender, NotifyEventArgs e)
{
MSG.Alert(e.Value);
}
public class MSG
{
static List<string> messages = new List<string>();
public static void Alert(string message)
{
messages.Add(message);
if (messages.Count == 1)
{
Show(messages.First());
}
}
private static async Task Show(string message)
{
MessageDialog md = new MessageDialog(message, "Title");
md.Commands.Add(
new UICommand("OK", new UICommandInvokedHandler((cmd) =>
{
messages.RemoveAt(0);
})));
await md.ShowAsync();
while (messages.Count > 0)
{
await Show(messages.First());
}
}
}
I'm making a small chat :)
When a user is typing (or stopped typing), this is being signalled to other users, and only when user switches between typing or not (checking if the textarea is empty or not)
Now I want to prevent those signals from being sent too rapidly after one another.. I'm thinking that some settimeout could do it, but I don't know how or where to put it in my code:
var istyping = false;
var wastyping = false;
chatfield.keyup(function(e) {
if (e.keyCode != 13) {
function typesignal(state) {
channel.send(JSON.stringify({
username: username,
type: 'typing',
message: state
}));
}
if (chatfield.val()) {
istyping = true;
if (wastyping==false) {
typesignal(1);
wastyping = true;
}
} else {
istyping = false;
if (wastyping==true) {
typesignal(0);
wastyping = false;
}
}
}
});
You might call this 'throttling' and I've used it a bunch on things like autocomplete dropdowns so you don't kill the server on every keystroke. The JS standard library lets you clear timeouts, and also returns an id when setTimeout is called. So you can use this id to clear the timeout (prevent the callback from being called within the time period) if the function is called again within a certain period of time. So for example:
var timeId;
function throttle(callback, ms) {
if (timeId) {
clearTimeout(timeId);
}
timeId = setTimeout(callback, ms)
}
chatfield.keyup(function(e) {
throttle(your_fn, 500);
});
In case it's not clear, the setTimeout executes a function after a certain period of time, specified in milliseconds as the second parameter. So, if I call setTimeout(function(){},300) that function will be called after 300 ms. And I can also say, "cancel" that original request. So if I get another request before the first one has fired, just cancel it and start over. That's the pattern I was trying to describe above :-)
I'd do this
chatfield.keyup(function(e) {
if (e.keyCode != 13) {
function typesignal(state) {
channel.send(JSON.stringify({
username: username,
type: 'typing',
message: state
}));
}
if (chatfield.val()) {
istyping = true;
if (wastyping==false) {
typesignal(1);
wastyping = true;
}
} else {
istyping = false;
if (wastyping==true) {
typesignal(0);
wastyping = false;
}
}
}
function doNothing() {
}
setTimeout("doNothing()",1000);
});
Background
I have an existing extension designed to accompany a browser-based game (The extension is mine, the game is not). The extension had been scraping the pages as they came in for the data it needed and making ajax requests for taking any actions.
Problem
The game developers recently changed a number of actions on the site to use ajax requests and I am thus far unable to get the data from those requests.
What I have so far
function TracingListener() {
}
TracingListener.prototype =
{
originalListener: null,
receivedData: [], // array for incoming data.
onDataAvailable: function(request, context, inputStream, offset, count)
{
var binaryInputStream = CCIN("#mozilla.org/binaryinputstream;1",
"nsIBinaryInputStream");
var storageStream = CCIN("#mozilla.org/storagestream;1", "nsIStorageStream");
binaryInputStream.setInputStream(inputStream);
storageStream.init(8192, count, null);
var binaryOutputStream = CCIN("#mozilla.org/binaryoutputstream;1",
"nsIBinaryOutputStream");
binaryOutputStream.setOutputStream(storageStream.getOutputStream(0));
// Copy received data as they come.
var data = binaryInputStream.readBytes(count);
this.receivedData.push(data);
binaryOutputStream.writeBytes(data, count);
this.originalListener.onDataAvailable(request, context,storageStream.newInputStream(0), offset, count);
},
onStartRequest: function(request, context) {
this.originalListener.onStartRequest(request, context);
},
onStopRequest: function(request, context, statusCode)
{
try {
if (request.originalURI && piratequesting.baseURL == request.originalURI.prePath && request.originalURI.path.indexOf("/index.php?ajax=") == 0) {
dump("\nProcessing: " + request.originalURI.spec + "\n");
var date = request.getResponseHeader("Date");
var responseSource = this.receivedData.join();
dump("\nResponse: " + responseSource + "\n");
piratequesting.ProcessRawResponse(request.originalURI.spec, responseSource, date);
}
} catch(e) { dumpError(e);}
this.originalListener.onStopRequest(request, context, statusCode);
},
QueryInterface: function (aIID) {
if (aIID.equals(Ci.nsIStreamListener) ||
aIID.equals(Ci.nsISupports)) {
return this;
}
throw Components.results.NS_NOINTERFACE;
}
}
hRO = {
observe: function(aSubject, aTopic, aData){
try {
if (aTopic == "http-on-examine-response") {
if (aSubject.originalURI && piratequesting.baseURL == aSubject.originalURI.prePath && aSubject.originalURI.path.indexOf("/index.php?ajax=") == 0) {
var newListener = new TracingListener();
aSubject.QueryInterface(Ci.nsITraceableChannel);
newListener.originalListener = aSubject.setNewListener(newListener);
dump("\n\nObserver Processing: " + aSubject.originalURI.spec + "\n");
for (var i in aSubject) {
dump("\n\trequest." + i);
}
}
}
} catch (e) {
dumpError(e);
}
},
QueryInterface: function(aIID){
if (aIID.equals(Ci.nsIObserver) ||
aIID.equals(Ci.nsISupports)) {
return this;
}
throw Components.results.NS_NOINTERFACE;
}
};
var observerService = Cc["#mozilla.org/observer-service;1"] .getService(Ci.nsIObserverService);
observerService.addObserver(hRO, "http-on-examine-response", false);
What's happening
The above code is notified properly when an http request is processed. The uri is also available and is correct (it passes the domain/path check) but the responseSource that gets dumped is, as far as I can tell, always the contents of the first http request made after the browser opened and, obviously, not what I was expecting.
The code above comes in large part from http://www.softwareishard.com/blog/firebug/nsitraceablechannel-intercept-http-traffic/. I'm really hoping that it's just something small that I've overlooked but I've been banging my head against the desk for days on this one, and so now I turn to the wisdom of SO. Any ideas?
but the responseSource that gets
dumped is, as far as I can tell,
always the contents of the first http
request made after the browser opened
and, obviously, not what I was
expecting.
There is a problem with the code above. The "receivedData" member is declared on prototype object and have empty array assigned. This leads to every instantiation of the TracingListener class to be using the same object in memory for receivedData. Changing your code to might solve he problem:
function TracingListener() {
this.receivedData = [];
}
TracingListener.prototype =
{
originalListener: null,
receivedData: null, // array for incoming data.
/* skipped */
}
Not sure though if this will solve your original problem.