i'm making a javascript widget (for the thingsboard platform). the thingsboard site has some javascript code running (e.g. do_some_things) which i can not modify. my widget can define functions like func_1 that will be run by the thingsboard site.
//### THINGSBOARD CODE (can not modify!) ###
function do_some_things() {
...
func_1();
func_2();
...
}
//### WIDGET CODE (can modify!) ###
function func_1() {
socket = new WebSocket("ws://192.168.137.4:8081/");
socket.onmessage=function(evt) {
settings_string = evt.data;
}
/* wait for a message here!*/
return settings_string;
}
in func_1 i would like to return some string that i retrive from a websocket server. how do i block the execution of func_1 until i have the websocket message?
i've had a look at promises and await, but i don't see how that can help me as i cant allow func_2 to run before func_1 is done and has returned its value.
(i don't care if the whole site freezes while it's waiting for the websocket)
Thank you Bergi for the comment.
If you cannot modify do_some_things, you'll have a hard time. You
could queue your work, but if do_some_things ever expects a return
value then that will be impossible to provide synchronously. One
cannot block on a websocket. – Bergi
i accepted that the problem is not solveable in javascript as long as one can not edit the function do_some_things and wants to retrieve data via websockets.
i have now found a workaround by setting up a small http server on the same machine as the websocket server which provides a json file containing the return string. i can request the file in a way that blocks the execution of func_1 like so:
function func_1() {
var request = new XMLHttpRequest();
request.open('GET', "http://192.168.137.4:8082/", false);
request.send(null);
if (request.status == 200) {
return request.responseText;
} else {
return "";
}
}
as XMLHttp support synchronous requests unlike websocket.
Related
I've been teaching myself php and xml (among other languages) and while going through the xmlhttprequest tutorial on w3schools, I noticed the open() and send() functions are located at the end of the function and not before or out of it. This is a bit puzzling because how can one get a response from the server if the request has not yet been sent? It maybe be something simple that I have missed and I apologize if that's the case but can anyone help me with my dilemma? Thanks in advance
function loadDoc() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("demo").innerHTML = this.responseText;
}
};
xhttp.open("GET", "ajax_info.txt", true);
xhttp.send();
}
The code to read the data will be in a separate function that is assigned as an event handler.
That function won't run until the response is received.
Related: How do I return the response from an asynchronous call?
It probably doesn't matter on modern browsers, but fundamentally, it's so you set up the call before sending it. In particular, so that all the handlers have been attached before asking the XHR to do something. Compare:
// Example 1
var xhr = new XMLHttpRequest();
xhr.addEventListener("load", function() {
// Got the data
});
xhr.open("GET", "http://example.com");
xhr.send();
with
// Example 2
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://example.com");
xhr.send();
xhr.addEventListener("load", function() {
// Got the data
});
Browsers are not single-threaded, though they run JavaScript code in a single main thread (plus any web workers you create). So it's possible (though extraordinarily unlikely) that with Example 2, if the resource is in the browser's cache, a separate thread handling network calls could trigger the load event between the send and addEventListener calls on the JavaScript thread, see that there were no handlers registered, and not queue a task for the event loop to call the handler. Whereas with Example 1, if it triggers the load event immediately upon send, it sees an attached handler and queues a task to call it (which runs later, when the event loop comes around to processing that task).
Here's an example of that hypothetical scenario, showing the thread interaction:
Example 1 - Highly Theoretical Scenario
JavaScript Thread Network Thread
----------------------------------------- --------------
var xhr = new XMLHttpRequest();
xhr.addEventListener("load", function() {
// Got the data
});
xhr.open("GET", "http://example.com");
xhr.send();
(Within send: Start the send, handing
off to the network thread)
1. Start a GET on `xhr`
2. It's in cache, are there any load
handlers registered on `xhr`?
3. Yes, queue a task to call the handler
(Done with current task)
(Pick up next task)
Call the handler
vs
Example 2 - Highly Theoretical Scenario
JavaScript Thread Network Thread
----------------------------------------- --------------
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://example.com");
xhr.send();
(Within send: Start the send, handing
off to the network thread)
1. Start a GET on `xhr`
2. It's in cache, are there any load
handlers registered on `xhr`?
3. No, don't queue a task to call
the handler
xhr.addEventListener("load", function() {
// Got the data
});
(Done with current task)
(Pick up next task)
(No task, do nothing)
I very much doubt any current browser would actually do that (Example 2), and I'm not aware of XHR having had a problem like this in the past. But it's theoretically possible, and there was a very similar problem, circa 2008, with setting src on an img element before hooking the load event for it. However, browsers fixed that problem, and I'd be surprised to find they were open to the Example 2 scenario above now, either, even if they or may not have been at some point in the past.
In practice, I doubt it matters. But I'd still use Example 1 if I used XMLHttpRequest (I don't, I use fetch).
I've been looking at how to integrate AJAX calls into a Python Django application and I'm somewhat new to both. I have been following the advice here:
https://www.quora.com/Can-I-execute-a-Python-function-from-JavaScript
Which led to this and this respectively for AJAX and Django advice.Both made pretty good sense to me. The desired end result is that a template in this fourth folder down (dashboard) call a function in a file called logic.py under the api folder above it:
In a JavaScript file hooked up to my django template, I have the following code I stole from the AJAX resource I listed above and made some light edits to:
window.onerror = function() {
debugger;
}
// browser - safety
var request;
if (window.XMLHttpRequest) {
request = new XMLHttpRequest();
} else if(window.ActiveXObject) { // ie
try {
request = new ActiveXObject('Msxml2.XMLHTTP');
}
catch(e) {
try {
request = new ActiveXObject('Microsoft.XMLHTTP');
}
catch(e) {}
}
}
function step2() {
console.log('something');
}
function testLogin() {
request.open('POST', '../../../api/logic');
// I've also been trying ^^^ logic.py, if it matters
request.send(null);
console.log('testLogin ran');
step2();
}
request.onreadystatechange = function () {
if(request.readystate === 4) {
if(request.status === 200) {
console.log(request.responseText);
}
}
}
It still is hooked up to a URL POST action in the django views, so when I hit the submit button in question I see the following two requests get generated:
That is the correct filepath for that location:
So I'm wondering if I'm missing something either about the AJAX setup, or the way it needs to interact with Django, or some combination of the two. Other resources I've been consulting in looking into this:
Call Python function from Javascript code
https://codehandbook.org/python-flask-jquery-ajax-post/
https://www.makeuseof.com/tag/python-javascript-communicate-json/
https://bytes.com/topic/javascript/answers/737354-how-call-python-function-javascript
And I originally started way earlier in the day so there were a few more, but needless to say I didn't see my issue immediately from looking at any of them. Any help is much appreciated.
So this wound up being a quirk of the Django url setup, I can't believe I didn't figure it out but I hadn't been in that part of the code base for some time.
In our urls.py script, the place I was pinging (which was in the location of the URL described) had a redirect on it and for that reason, the traffic wasn't going to the place I thought.
I have a custom URL protocol handler cgit:[...]
It launches up a background process which configures some stuff on the local machine. The protocol works fine, i'm launching it from JavaScript (currently using document.location = 'cgit:[...]'), but i actually want JavaScript to wait until the associated program exits.
So basically the steps i want JavaScript to do:
JavaScript does something
JavaScript launches cgit:[...]
Javascript waits until cgit:[...] exits
JavaScript does something else
Code:
function launchCgit(params)
{
showProgressBar();
document.location="cgit:"+params;
document.addEventListener( /* CGit-Program exited event */, hideProgressBar );
}
or:
function launchCgit(params)
{
showProgressBar();
// setLocationAndWait("cgit:"+params);
hideProgressBar();
}
Any ideas if this is possible?
Since this isn't really an expected use of window.location I would doubt that there's an easy way. My recommendation would be to use an AJAX request and have the c++ program send a response when it's done. That way, whatever code needs to run after the c++ program can be run when the request completes.
As i didn't find a suitable way to solve my problem using ajax requests or anything similar, i finally solved my problem using a kind-of-ugly workarround including XmlHttpRequest
For launching the protocol i'm still using document.location=cgit:[...]
I'm using a server side system including "lock-files" - that's like generic dummy files, with generated names for each request.
Once the user requests to open the custom protocol, such a file is being generated on the server specifically for that one protocol-opening-request.
I created a folder called "$locks" on the server where these files are being placed in. Once the protocol-associated program exits, the appropriate file is being deleted.
The website continuously checks if the file for a request still exists using XmlHttpRequest and fires a callback if it doesn't (example timout between tests: 1 sec).
The structure of the new files is the following:
lockThisRequest.php: It creates a file in the $locks directory based on the req url-parameter.
unlockThisRequest.php: It deletes a file in the $locks directory; again based on the req url-parameter.
The JavaScript part of it goes:
function launchCgit(params,callback)
{
var lock = /* Generate valid filename from params variable */;
// "Lock" that Request (means: telling the server that a request with this ID is now in use)
var locker = new XmlHttpRequest();
locker.open('GET', 'lockThisRequest.php?req='+lock, true)
locker.send(null);
function retry()
{
// Test if the lock-file still exists on the server
var req = new XmlHttpRequest();
req.open('GET', '$locks/'+lock, true);
req.onReadyStateChanged=function()
{
if (req.readyState == 4)
{
if (req.status == 200)
{
// lock-file exists -> cgit has not exited yet
window.setTimeout(retry,1000);
}
else if (req.status == 404)
{
// lock-file not found -> request has been proceeded
callback();
}
}
}
req.send(null);
}
document.location = 'cgit:'+params; // execute custom protocol
retry(); // initialize lockfileCheck-loop
}
Ussage is:
launchCgit("doThisAndThat",function()
{
alert("ThisAndThat finished.");
});
the lockThisRequest.php-file:
<?php
file_put_contents("$locks/".$_GET["req"],""); // Create lock file
?>
and unlockThisRequest.php:
<?php
unlink("../\$locks/".$_GET["req"]); // Delete lock file
?>
The local program / script executed by the protocol can simply call something like:
#!/bin/bash
curl "http://servername/unlockThisRequest.php?req=$1"
after it finished.
As i just said this works, but it's anything else than nice (congratulations if you kept track of those instructions)
I'd rather prefered a more simple way and (important) this also may cause security issues with the lockThisRequest.php and unlockThisRequest.php files!
I'm fine with this solution, because i'm only using it on a password protected private page. But if you plan to use it on a public or non protected page, you may want to add some security to the php files.
Anyways, the solution works for me now, but if anyone finds a better way to do it - for example by using ajax requests - he/she would be very welcome to add that way to the respective stackoverflow-documentation or the like and post a link to it on this thread. I'd still be interested in alternative solutions :)
i cant find an answer to this
i have been learning ajax lately but i learned how to do it all in javascript
now i go swiming around ajax question here and almost all are using jquery
so i end up confused. should i use normal javascript or do it through jquery?
so what are the differences?
this is my normal approach
var xmlHttp = createXmlHttpRequestObject(); //you first create the object to this function global
function createXmlHttpRequestObject() //here you instruct the function
{
var xmlHttp; //here you tell it to use the local variable not the global version of it because this returns to the global with the propper values
if (window.XMLHttpRequest) //if the "window" or browser is aware of this Object 90% of browsers
{
xmlHttp = new XMLHttpRequest(); // if true then the variable is now equal to the heart of ajax
}
else //for internet explorer
{
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
return xmlHttp; //we return it back to daddy the global variable this objects does everything
//this object is everything in ajax for the most part
}
function process() //function that gets called on load of the body
{
if(xmlHttp) //if its not void or if you can run ajax
{
try //try catch statement are sort of required for the heart of things like ajax and server communication
{
xmlHttp.open("GET", "bacon.txt", true); //here 1st type of call 2nd from where 3rd
//is it true assyscronly or at the same time
//it does not start the connection to the server, its only sets up settings for the connection
xmlHttp.onreadystatechange = handleServerResponse; //anytime something changes[propertie]
//i want to call that function handleserverresponse
//begin communication
xmlHttp.send(null); //this is what communicates to the server makesure on ready statechane before this
//if the server responds you want to make sure everything is taking care of like what function onready state change is it going to call
//or what to do like open a text file in this case
} catch(e)
{
alert( e.toString() ); //alert the error message as a string on a popup
}
}
}
//handling the server response
function handleServerResponse()
{
theD = document.getElementById('theD'); //get the div in a var
if(xmlHttp.readyState==1) //if the connection to the server is established
{ //google crhome may not show this one, some browsers ignore some states
theD.innerHTML += "Status 1: server connection established<br>";
}
else if(xmlHttp.readyState==2) //request received, hey client i am the server and i received your request
{
theD.innerHTML += "Status 2: request reveived <br>";
}
else if(xmlHttp.readyState==3) //while is doing its thing
{
theD.innerHTML += "Status 3: processing request <br>";
}
else if(xmlHttp.readyState==4) //your request is finished and ready
{ //it means your response is ready but doesnt guaranteed no trouble
if(xmlHttp.status==200) //if the status is 200 then is succesufll
{
//IF everthing finally good THE GOOD PART
try //put all your calls on a try statement REMEMBER
{
//get the txt file as a string
text = xmlHttp.responseText; //response text n a normal string
theD.innerHTML += "Status 4: request is finished and response is finished";
theD.innerHTML += text;
}catch (e)
{
alert( e.toString() );
}
} else //for the other statuses like 404 else somehting went wrong
{
alert( xmlHttp.statusText ); //this will give you a status report on the wrong
}
}
}
jQuery simply wraps all of the XmlHttpRequest calls into a simple to use library. In the guts of jQuery you will see code that creates the XmlHttpRequest objects.
You can see the code that does this here:
https://github.com/jquery/jquery/blob/master/src/ajax/xhr.js
The nice thing about using a framework like jQuery is that they handle a lot of the browser idiosyncrasies for you. They also handle a lot of the edge cases you might not think about when writing your code.
Using jQuery is just for ease of use. If you prefer doing it the javascript way then carry on doing that.
jQuery ajax calls do exactly the same as what you are doing but jQuery is a javascript framework which simplifies what you write.
jQuery is a javascript framework which contains library of simplified functions compared to the Native Javascript. One of the functions is the XMLHttpRequest.
This way we just need to implement functions that is needed to implement without needed to write the traditional codes to setup the AJAX system to work
You may learn more about jQuery ajax here:
http://api.jquery.com/jQuery.ajax/
I have to request data for a JS-script from a MySQL database (based upon a user-id).
I did not find a simple solution for JavaScript and it was not possible to load the data using ajax, because the database is available under a different domain.
I implemented a workaround using PHP and curl.
Now the JS has to "wait" for the request to finish, but the script is of course running asynchronously and does not wait for the response.
I know that it's not really possible to wait in JS, but it must be possible to return value like this.
I also tried using a return as another callback, but that didn't work of course, because the getter-function will run further anyway.
How can I implement a simple getter, which "waits" and returns the response from the HTTP-request?
Thanks for any other clues. I'm really lost at the moment.
This is a excerpt from the source code:
/**
* Simple getter which requests external data
*/
function simple_getter() {
// http request using a php script, because ajax won't work crossdomain
// this request takes some time. function finished before request is done.
/* Example */
var url = "http://example-url.com/get_data.php?uid=1234";
var response_callback = handle_result_response;
var value = send_request( url, response_callback );
value = value.split('*')[0];
if (value === '' || value == const_pref_none) {
return false;
}
/* 1. returns undefinied, because value is not yet set.
2. this as a callback makes no sense, because this function
will run asynchronous anyway. */
return value;
}
Additional information about the used functions:
/**
* Callback for the send_request function.
* basically returns only the responseText (string)
*/
function handle_result_response(req) {
// do something more, but basically:
return req.responseText;
}
/**
* Requests data from a database (different domain) via a PHP script
*/
function send_request( url, response_callback ) {
var req = createXMLHTTPObject();
if (!req)
return;
var method = (postData) ? "POST" : "GET";
req.open(method, url, true);
req.setRequestHeader('User-Agent','XMLHTTP/1.0');
// More not relevant source code
// ...
req.onreadystatechange = function () {
// More not relevant source code
// ...
response_callback(req);
}
if (req.readyState == 4)
return;
req.send(postData);
}
Not really relevant code, but required for the HTTP-request:
var XMLHttpFactories = [
function () {return new XMLHttpRequest()},
function () {return new ActiveXObject("Msxml2.XMLHTTP")},
function () {return new ActiveXObject("Msxml3.XMLHTTP")},
function () {return new ActiveXObject("Microsoft.XMLHTTP")}
];
function createXMLHTTPObject() {
var xmlhttp = false;
for (var i=0; i<XMLHttpFactories.length; i++) {
try {
xmlhttp = XMLHttpFactories[i]();
} catch (e) {
continue;
}
break;
}
return xmlhttp;
}
You really, really shouldn't try to synchronously wait for a network request to complete. The request may never complete, may hang and take a long time, and so on. Since JavaScript is single threaded, and in fact all major browser engines are single threaded, this will cause your entire page to hang while waiting for the request, and in some browsers, may cause the entire browser to hang.
What you should do is replace code like this:
var returned = some_request('http://example.com/query');
do_something_with(returned);
with code like this:
some_request('http://example.com/query', function (returned) {
do_something_with(returned);
});
That way, you will never cause your page or the browser to hang waiting for the request, and can simply do the work once the response comes in.
I don't see whats wrong with your code in general.
When you make a request, provide a Callback. When a response comes back, which you can easily detect, execute the Callback and pass it the result.
This is the way client side apps work.It is not procedural, but works by events.
You present the screen to the user and wait
The user makes an action
You call the server, set a callback and wait
The response come and you execute the callback and wait for another step 2
Rather than trying to change that, you need to fit with that or it will be a painful experience.
Javascript is not multithreaded. It means a single statement is run at a time. The real asynchronism come from the time the server takes to respond and call the callback. You never know which call will come first and need to build your program with that in mind.