Does a Firefox Workers limit exist? - javascript

Im trying to create web Workers and post messages to them in cycle:
array.forEach(function (data) {
this.createWorker();
this.workers[this.workersPointer].postMessage({task: 'someTask', data: string});
}, this);
createWorker function:
createWorker: function () {
this.workersPointer++;
var worker = this.workers[this.workersPointer] = new Worker('Worker.js'),
storage = this;
worker.onmessage = function (event) {
if (event.data.error) {
storage[event.data.task + 'Errback'](event.data.error);
}
else {
storage[event.data.task + 'Callback'](event.data.data);
}
};
worker.onerror = function (error) {
storage.workerErrback(error);
};
}
Worker code:
self.addEventListener('message', function (event) {
self.postMessage({
data: data,
error: err,
task: event.data.task
});
}, false);
It works perfectly in Google Chrome. When I'm trying to run it in Firefox, it works only 20 times. Do Firefox web workers have a limit? I can't find information about it on mozilla.org. If there is no limit, what's the problem? Any ideas?

Just did some test of my own. For this, i changed the code a little bit:
Cycle:
for(var i=0;i<200;i++){
this.createWorker();
this.workers[this.workersPointer].postMessage({task: 'someTask', number:i});
};
createWorker function:
this.workers =[];
this.workersPointer = 0;
storage=[];
var createWorker= function () {
workersPointer++;
var myPointer = workersPointer;
var worker = this.workers[this.workersPointer] = new Worker('Worker.js');
worker.onmessage = function (event) {
if (event.data.error) {
alert(event.data.error);
}
else {
document.cookie=event.data.task+"["+myPointer+"]="+event.data.number;
}
};
worker.onerror = function (event) {
alert("Error: " + event.error);
};
}
Worker:
onmessage = function(event) {
postMessage({number:event.data.number*2, task: event.data.task});
};
After i run this, in chrome i got 66 cookies (including a nice blue crash window), in firefox i got 20. So both browsers seem to have worker limitations.
EDIT:
In Opera i get a console message:
Maximum number of Web Worker instances(16) exceeded for this window.

There is a setting in Firefox, called "dom.workers.maxPerDomain" which is by default 20.
However, there might not be any real performance gain in using more workers than you have cores in the computer. With a modern computer today that has hyper threading, I think using around 8 workers would be sufficient. Otherwise you might cause to much context switching that would instead introduce a bottleneck.
It all depends though, what you want to achieve.

For futher reference check out in Firefox
about:config
There's a parameter called :
dom.workers.maxPerDomain
Wich (at least in FF 33) is set to a default value of 20.
gl.
And as noted on this other stackoverflow question:
Each browser has web workers limitations (Firefox has 20, Chrome 60+, Opera 16); however, you can change it in Firefox -> dom.workers.maxPerDomain; as for your actual question, if you can or cannot avoid this limitation, I'm not sure. "Workers (as these background scripts are called herein) are relatively heavy-weight, and are not intended to be used in large numbers." Can you give an exact situation where you would want to use more than 20 workers? – Marius Balaban Nov 26 '12 at 22:34

I also played around with workers and tried to find an optimum for my case (encryption of strings). It was 8 too.
Similar question and discussion: Number of Web Workers Limit

Related

How to set playback rate from chrome browser?

This one if probably for chromecast API devs.
Android and iOS have a setPlaybackRate method, but the Chrome Sender API doesn't appear to have an equivalent feature.
Is there a javascript method to do this besides using sendMessage?
If not, please consider this a feature request! :D
I know you've long since moved on from this problem, but here is what got me rolling on this, and yours was the only question I found about it.
playerTarget.setHalfSpeed = function (){
var media = castSession.getMediaSession();
castSession.sendMessage("urn:x-cast:com.google.cast.media",{
type: "SET_PLAYBACK_RATE",
playbackRate: 0.5,
mediaSessionId: media.mediaSessionId,
requestId: 2
}).then(
function (a) { console.log('Set playback rate success'); },
function (errorCode) {
console.log('Set playback rate error: ' + errorCode);
});
}.bind(this);

node-serialport on windows with multiple devices hangs

I've been experimenting with node-serialport library to access devices connected to a USB hub and send/receive data to these devices. The code works fine on linux but on windows(windows 8.1 and windows 7) I get some odd behaviour. It doesn't seem to work for more than 2 devices, it just hangs when writing to the port. The callback for write method never gets called. I'm not sure how to go about debugging this issue. I'm not a windows person, if someone can give me some directions it would be great.
Below is the code I'm currently using to test.
/*
Sample code to debug node-serialport library on windows
*/
//var SerialPort = require("./build/Debug/serialport");
var s = require("./serialport-logger");
var parsers = require('./parsers');
var ee = require('events');
s.list(function(err, ports) {
console.log("Number of ports available: " + ports.length);
ports.forEach(function(port) {
var cName = port.comName,
sp;
//console.log(cName);
sp = new s.SerialPort(cName, {
parser: s.parsers.readline("\r\n")
}, false);
// sp.once('data', function(data) {
// if (data) {
// console.log("Retrieved data " + data);
// //console.log(data);
// }
// });
//console.log("Is port open " + sp.isOpen());
if(!sp.isOpen()) {
sp.open(function(err) {
if(err) {
console.log("Port cannot be opened manually");
} else {
console.log("Port is open " + cName);
sp.write("LED=2\r\n", function(err) {
if (err) {
console.log("Cannot write to port");
console.error(err);
} else {
console.log("Written to port " + cName);
}
});
}
});
}
//sp.close();
});
});
I'm sure you'd have noticed I'm not require'ing serialport library instead I'm using serialport-logger library it's just a way to use the serialport addons which are compiled with debug switch on windows box.
TLDR; For me it works by increasing the threadpool size for libuv.
$ UV_THREADPOOL_SIZE=20 && node server.js
I was fine with opening/closing port for each command for a while but a feature request I'm working on now needs to keep the port open and reuse the connection to run the commands. So I had to find an answer for this issue.
The number of devices I could support by opening a connection and holding on to it is 3. The issue happens to be the default threadpool size of 4. I already have another background worker occupying 1 thread so I have only 3 threads left. The EIO_WatchPort function in node-serialport runs as a background worker which results in blocking a thread. So when I use more than 3 devices the "open" method call is waiting in the queue to be pushed to the background worker but since they are all busy it blocks node. Then any subsequent requests cannot be handled by node. Finally increasing the thread pool size did the trick, it's working fine now. It might help someone. Also this thread definitely helped me.
As opensourcegeek pointed all u need to do is to set UV_THREADPOOL_SIZE variable above default 4 threads.
I had problems at my project with node.js and modbus-rtu or modbus-serial library when I tried to query more tan 3 RS-485 devices on USB ports. 3 devices, no problem, 4th or more and permanent timeouts. Those devices responded in 600 ms interval each, but when pool was busy they never get response back.
So on Windows simply put in your node.js environment command line:
set UV_THREADPOOL_SIZE=8
or whatever u like till 128. I had 6 USB ports queried so I used 8.

Poor network performance with Websockets running on apple device

I am working on an HTML/Javascript running on mobile devices that is communicating with a Qt/C++ application running on a PC. Both the mobile device and the PC are on a local network. The communication between the HTML page (client) and the C++ app (server) is done using Websockets.
The HTML page is a remote control for the C++ application, so it is needed to have a low latency connection between the mobile device and the PC.
When using any non-Apple device as a client, data is sent to a rate between 60 to 120 frames/sec, which is totally acceptable. When using an Apple device, this rate falls to 3-4 frames/sec.
I also checked ping times (Websocket implementation, not a ping command from command line). They are acceptable (1-5 ms) for Apple devices as long as the device is not transmitting data. Whenever it transmits data, this ping time raises to 200ms.
Looking from the Javascript side, the Apple devices always send data at a consistent rate of 60 frames/sec, as any other devices do. However, on the server side, only 3 to 4 of these 60 frames are received when the client is an Apple device.
Does anyone have any idea on what can be happening?
Here is my Javascript code :
<script language="javascript" type="text/javascript">
var wsUri = document.URL.replace("http", "ws");
var output;
var websocket;
function init()
{
output = document.getElementById("output");
wsConnect();
}
function wsConnect()
{
console.log("Trying connection to " + wsUri);
try
{
output = document.getElementById("output");
websocket = new WebSocket(wsUri);
websocket.onopen = function(evt)
{
onOpen(evt)
};
websocket.onclose = function(evt)
{
onClose(evt)
};
websocket.onmessage = function(evt)
{
onMessage(evt)
};
websocket.onerror = function(evt)
{
onError(evt)
};
}
catch (e)
{
console.log("Exception " + e.toString());
}
}
function onOpen(evt)
{
alert("Connected to " + wsUri);
}
function onClose(evt)
{
alert("Disconnected");
}
function onMessage(evt)
{
alert('Received message : ' + evt.data);
}
function onError(evt)
{
alert("Error : " + evt.toString());
}
function doSend(message)
{
websocket.send(message);
}
window.addEventListener("load", init, false);
</script>
Data is sent from Javascript side using dosend() function.
Few ideas and suggestions.
Check if the client's WebSocket protocol is supported by the server. This question and answer discuss a case where different protocol versions were an issue.
The WebSocket standard permits implementations to arbitrarily delay transmissions and perform fragmentation. Additionally, control frames, such as Ping, do not support fragmentation, but are permitted to be interjected. These permitted behavioral difference may be contributing to the difference in times.
Check if the bufferedAmount attribute on the WebSocket to determine if the WebSocket is buffering the data. If the bufferedAmount attribute is often zero, then data has been passed to the OS, which may be buffering it based on OS or socket configurations, such as Nagle.
This question and answer mentions resolving delays by having the server send acknowledgements for each message.
To get a deeper view into the interactions, it may be useful to perform a packet trace. This technical Q&A in the Mac Developer Library may provide some resources as to how to accomplish this.
The best way to get some more insight is to use the AutobahnTestsuite. You can test both clients and servers with that suite and find out where problems are situated.
I have created QWebSockets, a Qt based websockets implementation, and used that on several occasions to create servers. Performance from Apple devices is excellent.
However, there seems to be a severe problem with Safari when it comes to large messages (see https://github.com/KurtPattyn/QWebSockets/wiki/Performance-Tests). Maybe that is the problem.

How to know if the network is (dis)connected?

How can I know, in Xul, if the network is (dis)connected?
--update
Using:
function observe(aSubject, aTopic, aState) {
if (aTopic == "network:offline-status-changed") {
write("STATUS CHANGED!");
}
}
var os = Components.classes["#mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
os.addObserver(observe, "network:offline-status-changed", false);
and the preference:
pref("network.manage-offline-status", true);
it's not working.. There's a bug report here, but I don't think it has something to do with it.
--
Actually I think it's not possible to be notified, as even in Firefox we're never notified, and the user need to manually mark "work offline" if he wants the browser to know that it's offline..
--
Screenshot my of Firefox "about:config" filtering for "offline" string, unfortunately, there no "network.manage-offline-status":
You should be able to use navigator.onLine. Here is the help page
https://developer.mozilla.org/en/Online_and_offline_events
navigator.onLine is a property that
maintains a true/false value (true for
online, false for offline). This
property is updated whenever the user
switches into "Offline Mode" by
selecting the corresponding menu item
(File -> Work Offline in Firefox).
Another solution (as commented by #Neil):
Components.classes["#mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService)
.addObserver(myF­unction, "network:offline-status-changed", false);
The best way I found is to use the following javascript code, that behaves like a ping, and make the test with some big websites, and assume that if none of them answers, so the network must be disconnected.
var ping = {};
ping = {
img:null,
imgPreload:null,
timer:null,
init:function() {
var sess = new Date();
var nocache = sess.getTime();
var imguri = ping.img+"?time="+nocache;
var ping.imgPreload = new Image();
ping.imgPreload.onload = function() {
clearTimeout(ping.timer);
ping.timer = null;
alert("Domain is available");
};
ping.imgPreload.src = imguri;
ping.timer = setTimeout("ping.fail_to_ping()",60000);
},
fail_to_ping:function() {
clearTimeout(ping.timer);
ping.timer = null;
ping.imgPreload = null;
alert("Ping to domain failed!");
}
};
(from http://crynobone.com/ci/index.php/archive/view/852)
--update
But, as it's not a reliable solution (as you can't rely that the image will be in the website forever), the best solution might be to develop a new XPCom component.
Eh... as per HTML5 (read echmascript 5), the on-/offline events are available.
See it here at Mozilla Hacks
Edit 20/4/2011:
I just encountered an update for this answer, when i was watching a podcast from MS MIX11:
http://channel9.msdn.com/Events/MIX/MIX11/HTM14 around time 43:36, the lecturer is actually talking about the window.navigator.onLine property, where he uses it for detecting if the browser (and the computer) is online. Then he uses the online event to do something when he gets online again.
This method is only available in modern browsers, however. So IE 8 and below have to poll for the connection.

How to check if a custom protocol supported

We are using software that registers its own protocol. We can run application from browser then by link like:
customprotocol://do_this.
but is there a way to check is such custom protocol supported by user`s system? If not we would like to ask user to install software first.
E.g:
if (canHandle ('customprotocol')) {
// run software
}
else {
// ask to install
}
Edit
I know about protocolLong property but it works only in IE.
Unfortunately, there's no easy way of achieving this. There's certainly no method of pre-determining whether or not the protocol handler is installed.
Internet Explorer, as you mentioned, has the protocolLong property but I'm having trouble getting it to return anything other than "Unknown Protocol" for all custom protocol handlers -- if anyone knows how to get IE to return the correct value please let me know so I can update this section. The best solution I've found with IE is to append to the user agent string or install a browser extension along with your app that exposes a Javascript accessible property.
Firefox is by far the easiest of the major browsers, as it will allow you to try and catch a navigation attempt that fails. The error object returned contains a name property whose value is NS_ERROR_UNKNOWN_PROTOCOL:
try {
iframe.contentWindow.location.href = "randomprotocolstring://test/";
} catch(e) {
if (e.name == "NS_ERROR_UNKNOWN_PROTOCOL")
window.location = "/download/";
}
Firefox will pop up with its own alert box:
Firefox doesn't know how to open this address, because the protocol (randomprotocolstring) isn't associated with any program.
Once you close this box, the catch block will execute and you have a working fallback.
Second is Opera, which allows you to employ the laws of predictability to detect success of a custom protocol link clicked. If a custom protocol click works, the page will remain the same location. If there is no handler installed, Opera will navigate to an error page. This makes it rather easy to detect with an iframe:
iframe.contentWindow.location = "randomprotocolstring://test/";
window.setTimeout(function () {
try {
alert(ifr.contentWindow.location);
} catch (e) { window.location = "/download/"; }
}, 0);
The setTimeout here is to make sure we check the location after navigation. It's important to note that if you try and access the page, Opera throws a ReferenceException (cross-domain security error). That doesn't matter, because all we need to know is that the location changed from about:blank, so a try...catch works just fine.
Chrome officially sucks with this regard. If a custom protocol handler fails, it does absolutely zip. If the handler works... you guessed it... it does absolutely zip. No way of differentiating between the two, I'm afraid.
I haven't tested Safari but I fear it would be the same as Chrome.
You're welcome to try the test code I wrote whilst investigating this (I had a vested interest in it myself). It's Opera and Firefox cross compatible but currently does nothing in IE and Chrome.
Here's an off-the-wall answer: Install an unusual font at the time you register your custom protocol. Then use javascript to check whether that font exists, using something like this.
Sure it's a hack, but unlike the other answers it would work across browsers and operating systems.
Just to chime in with our own experience, we used FireBreath to create a simple cross-platform plugin. Once installed this plugin registers a mime type which can be detected from the browser javascript after a page refresh. Detection of the mime type indicates that the protocol handler is installed.
if(IE) { //This bastard always needs special treatment
try {
var flash = new ActiveXObject("Plugin.Name");
} catch (e) {
//not installed
}
else { //firefox,chrome,opera
navigator.plugins.refresh(true);
var mimeTypes = navigator.mimeTypes;
var mime = navigator.mimeTypes['application/x-plugin-name'];
if(mime) {
//installed
} else {
//not installed
}
}
Internet Explorer 10 on Windows 8 introduced the very useful navigator.msLaunchUri method for launching a custom protocol URL and detecting the success or failure. For example:
if (typeof (navigator.msLaunchUri) == typeof (Function)) {
navigator.msLaunchUri(witchUrl,
function () { /* Success */ },
function () { /* Failure */ showError(); });
return;
}
Windows 7 / IE 9 and below support conditional comments as suggested by #mark-kahn.
For Internet Explorer, the best solution I've found is to use Conditionl comments & Version Vector (application must write something to registry while installing protocol, see http://msdn.microsoft.com/en-us/library/ms537512.aspx#Version_Vectors). protocolLong doesn't work for custom protocol.
On mobile you can use an embedded iframe to auto switch between the custom protocol and a known one (web or app store), see https://gist.github.com/2662899
I just want to explain more previous Mark's answer (some people did not understand for example user7892745).
1) When you launch you web-page or web-application it checks for an unusual font (something like Chinese Konfuciuz font http://www.fontspace.com/apostrophic-lab/konfuciuz).
Below is the code of sample web-page with function which checks the font (called isFontAvailable):
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script>
/**
* Checks if a font is available to be used on a web page.
*
* #param {String} fontName The name of the font to check
* #return {Boolean}
* #license MIT
* #copyright Sam Clarke 2013
* #author Sam Clarke <sam#samclarke.com>
*/
(function (document) {
var width;
var body = document.body;
var container = document.createElement('span');
container.innerHTML = Array(100).join('wi');
container.style.cssText = [
'position:absolute',
'width:auto',
'font-size:128px',
'left:-99999px'
].join(' !important;');
var getWidth = function (fontFamily) {
container.style.fontFamily = fontFamily;
body.appendChild(container);
width = container.clientWidth;
body.removeChild(container);
return width;
};
// Pre compute the widths of monospace, serif & sans-serif
// to improve performance.
var monoWidth = getWidth('monospace');
var serifWidth = getWidth('serif');
var sansWidth = getWidth('sans-serif');
window.isFontAvailable = function (font) {
return monoWidth !== getWidth(font + ',monospace') ||
sansWidth !== getWidth(font + ',sans-serif') ||
serifWidth !== getWidth(font + ',serif');
};
})(document);
function isProtocolAvailable()
{
if (isFontAvailable('Konfuciuz'))
{
return true;
}
else
{
return false;
}
}
function checkProtocolAvail()
{
if (isProtocolAvailable())
{
alert('Custom protocol is available!');
}
else
{
alert('Please run executable to install protocol!');
}
}
</script>
<h3>Check if custom protocol was installed or not</h3>
<pre>
<input type="button" value="Check if custom protocol was installed!" onclick="checkProtocolAvail()">
</body>
</html>
2) First time when user opens this page, font will not be installed so he will get a message saying "Please run executable to install custom protocol...".
3) He will run executable which will install the font. Your exe can just copy the font file (in my case it is KONFUC__.ttf) into C:\Windows directory or using a code like this (example on Delphi):
// Adding the font ..
AddFontResource(PChar('XXXFont.TTF'));
SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
4) After that, when user runs web app again, he gets "Custom protocol is available!" message because font was installed this time.
Tested on Google Chrome, Internet Explorer and Firefox - working great!
For Firefox, most of articles I googled, including Andy E 's answer here, and this gist Cross-browser implementation of navigator.msLaunchUri or https://github.com/ismailhabib/custom-protocol-detection using
iframe.contentWindow.location.href = uri
But it has stopped working since Firefox 64, e.g here https://github.com/ismailhabib/custom-protocol-detection/issues/37 also confirmed that.
So FF 64+ I found I can either using Chrome's method, blurHandler or using the post there https://github.com/ismailhabib/custom-protocol-detection/issues/37#issuecomment-617962659
try {
iframe.contentWindow.location.href = uri;
setTimeout(function () {
try {
if (iframe.contentWindow.location.protocol === "about:") {
successCb();
} else {
failCb();
}
} catch (e) {
if (e.name === "NS_ERROR_UNKNOWN_PROTOCOL" ||
e.name === "NS_ERROR_FAILURE" || e.name === "SecurityError") {
failCb();
}
}
}, 500);
} catch (e) {
if (e.name === "NS_ERROR_UNKNOWN_PROTOCOL" || e.name === "NS_ERROR_FAILURE"
|| e.name === "SecurityError") {
failCb();
}
}
For Chrome 86+ it also fails to work, check my answer for details Detect Custom Protocol handler in chrome 86
BTW, I find most of answers/articles are outdated in some cases.

Categories