TLDR: What is an alternative to WorkerGlobalScope.close() which is not deprecated
I want to close/stop/terminate a Javascript web worker from the inside, after its job is done, since there is a setInterval() which keeps being active even after the main work is done.
Reading this SO question (JavaScript Web Worker - close() vs terminate()), it seems like self.close() is what I'm searching for. But apparently this is deprecated (stated here) without any mention of alternatives.
The only alternative I have come up with so far would be to send a message to the main thread which then invokes a worker.terminate() call, but that seems like overkill since I would then need to check every message that comes this way for a termination request.
Am I missing something? What should I use?
This notice is misleading .close() is not deprecated at all.
What happens here is that in the specs WorkerGlobalScope is an interface that is used by different worker types (DedicatedWorkers, ServiceWorkers, SharedWorkers, and maybe other Worklets in other specs).
All these types don't have a .close method (e.g ServiceWorkers don't), and thus this method has been moved to each specific types of worker global scope's definition.
For instance you can see that for the DedicatedWorkerGlobalScope, it's still here, and isn't scheduled to be deprecated any time soon.
And it's actually also there in MDN.
Related
I know these types of question come up fairly often, but I need help with a wait-like mechanism in JavaScript. I know setTimeout-based solutions are going to come up, but I'm not sure how to pull it off in my case.
I'm writing an API that uses a WebSocket internally. There's a connect() method that sets up the WebSocket, and I need to make it not return until after the WebSocket is set up. I'd like it to return a value for whether or not the connection was successful, but that's not the main problem.
The issue I'm hitting is that after a user calls connect(), they may call another method that relies on the WebSocket to be properly set up. If it's called too early, an error is thrown stating that the object is not usable.
My current solution is setting a "connected" flag when I've determined a successful connection and in each method checking for it in each method. If it's not connected, I add the method call to a queue that is ran through by the same code that sets the flag. This works, but it introduces that style of code all over my methods and also seems misleading from the user-perspective, since the call of those functions is deferred. Also, if there is other user code that relies on those calls being completed before it gets to them, it won't behave as expected.
I've been racking my brain with how to handle this case. The easiest solution is to just find a way to block returning from connect until after the WebSocket is set up, but that's not really the JavaScript way. The other option was to make them provide the rest of their code in a callback, but that seems like a weird thing to do in this case. Maybe I'm over-thinking it?
Edit: To better illustrate my problem, here's a example of what the user could do:
var client = new Client(options);
client.connect();
client.getServerStatus();
The getServerStatus() method would be using the WebSocket internally. If the WebSocket is not set up yet, the user will get that not usable error.
Todays Javascript does not really work like that unfortunately. In the future (ECMA6) there may be new language features that address this issue more directly. However for now you are stuck with the currently accepted method of handling asynchronous events, which is limited to callbacks. You may also want to explore 'promises' to handle 'callback hell' however you will need a library for this.
And yes it does seem strange to have callbacks everywhere, especially for someone new to web programming, however it is really the only way to go about it at this stage (assuming you want a cross-browser friendly solution).
"Wait" is almost the keyword you are looking for. Actually, it's yield that does this. See e.g. MDN's documentation.
There's a connect() method that sets up the WebSocket, and I need to make it not return until after the WebSocket is set up
That isn't going to happen unless you rewrite the javascript execution engine.
Either the code trying to send data will need to check the socket state (I'd go with encapsulating the socket in a object, supplying a method which sets a member variable on the open/close events and poll the state of that member variable from the external code). Alternatively you could add messages and call backs to a queue and process the queue when the socket connects.
I have been trying to find a solution to what seems to be relatively simple scenario. I have JavaScript running in an html page that makes a call to an XPcom that I have written in C++. So far, so good.
This XPcom retrieves a reference to the observer-service (do_GetService("#mozilla.org/observer-service;1")); fires a notify which is 'seen' by the JavaScript; the XPcom creates a windows thread (AFX), passes a copy of the observer-service reference and returns to the JavaScript caller; expecting the XPcom thread to send additional notifies at appropriate times (based on external events).
The notifies however fail to arrive in the JavaScript and my initial thought was the notify method will not deliver notifications from a 'different' thread. I've used the VStudio debugger to confirm the program sequence is as expected; ie the external event is being received by the thread and the notify method is being called... but, no notify event arrives.
I've read quite a few postings across the web and nothing really 'nails' the particular scenario I'm trying to address. I'm not married to the idea of using notify:
I've tried event notification via NS_DispatchToCurrentThread however that is not working out either because I don't have an "event" from the JavaScript side to deliver. I can create one of my own within the context of the XPcom and I can 'notify it'; but, that was just a POC to prove I could deliver events from XPcom; now I need for the JavaScript side to give me an event to notify;
I've tried passing a new'ed object as a nsiSupports arg; but, the DispatchToCurrentThread wants an nsiRunnable and I cannot figure out how to pass one of those (the idl file does not support);
I've also considered 'wrapping' the event with some sort of object that is compatible with nsiSupports; but, am unsure about the details of doing so.
The objective is quite simple. deliver asynchronous events or notifications from an XPcom thread to the main, or even sub, thread of the JavaScript; but, I'm getting less than 10% traction here.
Has anyone accomplished this, or have ideas as to how to get it done?
You are correct, the observer service works only on the main thread (check the return value of your Notify() call, it should be NS_ERROR_UNEXPECTED). You are also correct as far as the solution goes - dispatch an event to the main thread, via NS_DispatchToMainThread(). As to the actual implementation, function NS_NewRunnableMethod() should help (unless you want to create your custom nsIRunnable implementation - e.g. to pass parameters). You probably want to do something like this:
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(xpcomComponent, &nsMyComponent::processEvent);
nsresult rv = NS_DispatchToMainThread(event);
Here xpcomComponent would be a reference to your XPCOM component instance and nsMyComponent::processEvent its method that needs to be called on main thread. That method would then be able to notify the observer.
So I have this seriously recursive function that I would like to use with my code. The issue is it doesn't really take advantage of dual core machines because js is single threaded. I have tried using webworkers but don't really know much about multicore programming. Would someone point me to some material that could explain how it is done. I googled to find this sample link but its not really much help without documentation! =/
I would be glad if someone could show me how this could be done without webworkers though! That would be just awesome! =)
I came across this link on whatwg. This is really weird because it explains how to use multicore programming in webworkers etc, but on executing on my chrome browser it throws errors. Same goes with other browsers.
Error: 9Uncaught ReferenceError: Worker is not defined in worker.js
UPDATE (2018-06-21): For people coming here in search of multi-core programming in JavaScript, not necessarily browser JavaScript (for that, the answer still applies as-is): Node.js now supports multi-threading behind a feature flag (--experimental-workers): release info, relevant issue.
Writing this off the top of my head, no guarantees for source code. Please go easy on me.
As far as I know, you cannot really program in threads with JavaScript. Webworkers are a form of multi-programming; yet JavaScript is by its nature single-threaded (based on an event loop).
A webworker is seperate thread of execution in the sense that it doesn't share anything with the script that started it; there is no reference to the script's global object (typically called "window" in the browser), and no reference to any of your main script's variables other than data you send to the thread.
Think as the web worker as a little "server" that gets asked a question and provides an answer. You can only send strings to that server, and it can only parse the string and send back what it has computed.
// in the main script, one starts a worker by passing the file name of the
// script containing the worker to the constructor.
var w = new Worker("myworker.js");
// you want to react to the "message" event, if your worker wants to inform
// you of a result. The function typically gets the event as an argument.
w.addEventListener("message",
function (evt) {
// process evt.data, which is the message from the
// worker thread
alert("The answer from the worker is " + evt.data);
});
You can then send a message (a String) to this thread using its postMessage()-Method:
w.postMessage("Hello, this is my message!");
A sample worker script (an "echo" server) can be:
// this is another script file, like "myworker.js"
self.addEventListener("message",
function (evt) {
var data = JSON.parse(evt.data);
/* as an echo server, we send this right back */
self.postMessage(JSON.stringify(data))
})
whatever you post to that thread will be decoded, re-encoded, and sent back. of course you can do whatever processing you would want to do in between. That worker will stay active; you can call terminate() on it (in your main script; that'd be w.terminate()) to end it or calling self.close() in your worker.
To summarize: what you can do is you zip up your function parameters into a JSON string which gets sent using postMessage, decoded, and processed "on the other side" (in the worker). The computation result gets sent back to your "main" script.
To explain why this is not easier: More interaction is not really possible, and that limitation is intentional. Because shared resources (an object visible to both the worker and the main script) would be subject to two threads interfering with them at the same time, you would need to manage access (i.e., locking) to that resource in order to prevent race conditions.
The message-passing, shared-nothing approach is not that well-known mainly because most other programming languages (C and Java for example) use threads that operate on the same address space (while others, like Erlang, for instance, don't). Consider this:
It is really hard to code a larger project with mutexes (a mutual exclusion mechanism) because of the associated deadlock/race condition complexities. This is stuff that can make grown men cry!
It is really easy in comparison to do message-passing, shared-nothing semantics. The code is isolated; you know exactly what goes into your worker and what comes out of your worker. Deadlocks and race conditions are impossible to achieve!
Just try it out; it is capable of doing interesting things, probably all you want. Bear in mind that it is still implementation defined whether it takes advantage of multicore as far as I know.
NB. I just got informed that at least some implementations will handle JSON encoding of messages for you.
So, to give an answer to your question (it's all above; tl;dr version): No, you cannot do this without web workers. But there is nothing really wrong about web workers aside from browser support, as is the case with HTML5 in general.
As far as I remember this is only possible with the new HTML5 standard. The keyword is "Web-Worker"
See also:
HTML5: JavaScript Web Workers
JavaScript Threading With HTML5 Web Workers
Web workers are the answer to the client side. For NodeJS there are many approaches. Most popular - spawn several processes with pm2 or similar tool. Run single process and spawn/fork child processes. You can google around these and will find a lot of samples and tactics.
Web workers are already well supported by all browsers. https://caniuse.com/#feat=webworkers
API & samples: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers
I'm developing a SCORM compliant LMS, and having some problems with Captivate generated contents.
Basically, the behavior is: If you see a SCO (captivate generated content) with for example 15 slides and 1 question in each slide quickly, my lms is not tracking all the 15 question, only the first 3 or 4. If you wait a long time at the end, or if you take the content slow, it works fine.
After a lot of google searches, and debugging and tracing, finally, I found two main issues:
1) Captivate - SCORM API communication is asynchronous (is the same than flash - javascript communication). So, when the user see the content quickly, the function calls get more and more dealayed, and at the end, maybe the user is answering question 15, and the content is sending question 4 information. I cannot change the Flash or JS-Flash interface, because this is provided by Captivate.
There is a way to make this sync?? I mean, to force the flash wait some way?
2) The functions are taking longer each time they are called, for example, setValue takes 7 milliseconds the first time and 200 the last time is called.
To understand this problem, here is a little background:
Captivate contents (all contents really but more captivate) calls a specific function many times, the SetValue function, one of the SCORM API functions. This function takes two parameters (fieldName, value) the firstone is the name of the field to be set, and the second the new value. In my implementation, this function first validate the value using a regular expression, and then set the value in an object.
Ok, I can add a lot more info, but I don't know what is really important, I'm not hoping you fix my code without seeing it, but I'm out of ideas, and need new opinions, ideas, directions.... maybe that sombody ask the right question... help :)
Thanks
When publishing for SCORM, Captivate does not use synchronous communication methods.* Depending on the browser, Captivate uses either FSCommand or the old-school getURL method to communicate with the HTML file; the HTML file then uses JavaScript to relay the data to the LMS via the SCORM API.
The response (if any) is relayed from JavaScript to either FSCommand or a proxy SWF (for getURL), which is then monitored internally in Captivate via a callback function. This callback function uses timers, and that's probably where your problem lies.
If you're setting g_intAPIType to 0, you're forcing the browser to use FSCommand, which isn't supported in all browsers and operating systems. Setting g_intAPIType to 1 means you're forcing the browser to use getURL, which is cross-browser but has a few drawbacks (including lots of clicking sounds).
In both cases, the data is sent via an internal queue script, which uses the waitForResponse callback function.
The performance problems you're encountering are likely due to the queuing, and the asynchronous communication compounds the problem because of timers attached to waitForResponse. Changing g_intAPIType will probably only have a minor effect on your performance issues, though using getURL (g_intAPIType=1) may help improve consistency from browser to browser.
Regardless of the g_intAPIType settings, you cannot prevent the internal tracking mechanism from using the asynchronous waitForResponse function, so there is no way to stop Captivate from using timers when getting/setting data; over a period of time you will probably start to notice longer and longer delays like the ones you described, esp. if you're making a lot of calls to the LMS.
(* Small exception: I've been informed Captivate 4 and 5 use ExternalInterface if the project is built in AS3 and is published for SCORM 2004, but it appears the queue and waitForResponse timers are still used, basically treating ExternalInterface like the asynchronous methods listed above.)
Some Options:
You could change how you are doing the questions. Instead of 1 per frame put all the questions on 1 frame.
Otherwise, you will need to do some JavaScript magic in your SCORM Player JavaScript. I would start with minimizing the JS code with a tool like JSMin.
Then try to cache the JS files so they are only loaded once. I suspect that the files are being called over and over with each frame.
"There is a way to make this sync?? I mean, to force the flash wait some way?"
Apparently, the problem is this one :
"Captivate is the only SCO that calls SCORM JavaScript functions asynchronously. Firefox is the only browser that does not force synchronous communications between the SCO and the supporting JavaScript. When a Captivate SCO, running on Firefox, submits a status update to one of the JS functions, Captivate does not wait for a success or fail response before submitting the next status update. Since Captivate is quite verbose in its communications and JavaScript is not multithreaded, quiz status submissions can stack up and overwrite each other. This can cause a loss of data - especially for longer quizzes. [...]
If you'd like to see the asynchronous problem with any other LMS, take a long Captivate quiz using Firefox and answer the questions very quickly. Some of the questions near the end will get dropped.. " (interzoic.com forum)
And maybe a solution :
"The slow issue is resolved when I force the g_intAPIType to 0 (into the
.htm file), so it force Captivate to communicate as if it was into IE."
In captivate, while publishing a scorm you will see option "Send tracking data at the end",
Use this option, it will resolve your problem.
I have seen this link: Implementing Mutual Exclusion in JavaScript.
On the other hand, I have read that there are no threads in javascript, but what exactly does that mean?
When events occur, where in the code can they interrupt?
And if there are no threads in JS, do I need to use mutexes in JS or not?
Specifically, I am wondering about the effects of using functions called by setTimeout() and XmlHttpRequest's onreadystatechange on globally accessible variables.
Javascript is defined as a reentrant language which means there is no threading exposed to the user, there may be threads in the implementation. Functions like setTimeout() and asynchronous callbacks need to wait for the script engine to sleep before they're able to run.
That means that everything that happens in an event must be finished before the next event will be processed.
That being said, you may need a mutex if your code does something where it expects a value not to change between when the asynchronous event was fired and when the callback was called.
For example if you have a data structure where you click one button and it sends an XmlHttpRequest which calls a callback the changes the data structure in a destructive way, and you have another button that changes the same data structure directly, between when the event was fired and when the call back was executed the user could have clicked and updated the data structure before the callback which could then lose the value.
While you could create a race condition like that it's very easy to prevent that in your code since each function will be atomic. It would be a lot of work and take some odd coding patterns to create the race condition in fact.
The answers to this question are a bit outdated though correct at the time they were given. And still correct if looking at a client-side javascript application that does NOT use webworkers.
Articles on web-workers:
multithreading in javascript using webworkers
Mozilla on webworkers
This clearly shows that javascript via web-workers has multithreading capabilities. As concerning to the question are mutexes needed in javascript? I am unsure of this. But this stackoverflow post seems relevant:
Mutual Exclusion for N Asynchronous Threads
Yes, mutexes can be required in Javascript when accessing resources that are shared between tabs/windows, like localStorage.
For example, if a user has two tabs open, simple code like the following is unsafe:
function appendToList(item) {
var list = localStorage["myKey"];
if (list) {
list += "," + item;
}
else {
list = item;
}
localStorage["myKey"] = list;
}
Between the time that the localStorage item is 'got' and 'set', another tab could have modified the value. It's generally unlikely, but possible - you'd need to judge for yourself the likelihood and risk associated with any contention in your particular circumstances.
See the following articles for a more detail:
Wait, Don't Touch That: Mutual Exclusion Locks & JavaScript - Medium Engineering
JavaScript concurrency and locking the HTML5 localStorage - Benjamin Dumke-von der Eh, Stackoverflow
As #william points out,
you may need a mutex if your code does something where it expects a
value not to change between when the asynchronous event was fired and
when the callback was called.
This can be generalised further - if your code does something where it expects exclusive control of a resource until an asynchronous request resolves, you may need a mutex.
A simple example is where you have a button that fires an ajax call to create a record in the back end. You might need a bit of code to protect you from trigger happy users clicking away and thereby creating multiple records. there are a number of approaches to this problem (e.g. disable the button, enable on ajax success). You could also use a simple lock:
var save_lock = false;
$('#save_button').click(function(){
if(!save_lock){
//lock
save_lock=true;
$.ajax({
success:function()
//unlock
save_lock = false;
}
});
}
}
I'm not sure if that's the best approach and I would be interested to see how others handle mutual exclusion in javascript, but as far as i'm aware that's a simple mutex and it is handy.
JavaScript is single threaded... though Chrome may be a new beast (I think it is also single threaded, but each tab has it's own JavaScript thread... I haven't looked into it in detail, so don't quote me there).
However, one thing you DO need to worry about is how your JavaScript will handle multiple ajax requests coming back in not the same order you send them. So, all you really need to worry about is make sure your ajax calls are handled in a way that they won't step on eachother's feet if the results come back in a different order than you sent them.
This goes for timeouts too...
When JavaScript grows multithreading, then maybe worry about mutexes and the like....
JavaScript, the language, can be as multithreaded as you want, but browser embeddings of the javascript engine only runs one callback (onload, onfocus, <script>, etc...) at a time (per tab, presumably). William's suggestion of using a Mutex for changes between registering and receiving a callback should not be taken too literally because of this, as you wouldn't want to block in the intervening callback since the callback that will unlock it will be blocked behind the current callback! (Wow, English sucks for talking about threading.) In this case, you probably want to do something along the lines of redispatching the current event if a flag is set, either literally or with the likes of setTimeout().
If you are using a different embedding of JS, and that executes multiple threads at once, it can get a bit more dicey, but due to the way JS can use callbacks so easily and locks objects on property access explicit locking is not nearly as necessary. However, I would be surprised if an embedding designed for general code (eg, game scripting) that used multi threading didn't also give some explicit locking primitives as well.
Sorry for the wall of text!
Events are signaled, but JavaScript execution is still single-threaded.
My understanding is that when event is signaled the engine stops what it is executing at the moment to run event handler. After the handler is finished, script execution is resumed. If event handler changed some shared variables then resumed code will see these changes appearing "out of the blue".
If you want to "protect" shared data, simple boolean flag should be sufficient.