Implement delay in javascript without killing the processor - javascript

I want to return the function when a certain time has passed. In my function below the return thing didn't work(the alert was triggered).
The thing is that in my handleRequestStateChange I initialize myArray.
function() {
xmlHttp.open("POST", "xxx", true);
xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlHttp.setRequestHeader("Content-Length", 10);
xmlHttp.onreadystatechange = handleRequestStateChange;
xmlHttp.send(locParam);
setTimeout(function() { return myArray; }, 5000);
alert("end sleep");
}
Thanks!

As you're aware, timers are delayed until later in the thread, but the function that calls them continues to execute straight away. There's no way to delay the currently executing function without locking up the browser and preventing user interaction with the browser.
This is where the point of callbacks come into play. Instead of trying to delay continued execution of code, you supply a function as a parameter to the "delaying" function, and when it has it's necessary data ready, it executes the callback function with the data as a parameter.
function submitRequest(callback) {
xmlHttp.open("POST", "xxx", true);
xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlHttp.setRequestHeader("Content-Length", 10);
xmlHttp.onreadystatechange = function ()
{
if (xmlHttp.readyState == 4 && xml.status == 200)
{
var myArray;
// do something with data
callback(myArray); // execute the callback function
}
};
xmlHttp.send(locParam);
}
function someCallingFunction()
{
// call submitRequest with an anonymous function as the callback parameter
submitRequest(function (myArray)
{
alert("end sleep");
// do something with myArray
});
}

You can put the sleep for certain time, then put the return statement after
the sleep.
So that it will return from the function after some time is passed.

Related

Not able to implement Asynchronous XMLHttpRequest in Javascript in the right way

I am using Async XMLHttpRequest to make an API call. Here's the workflow of my program,
first_function(){
var valueToBeReturned = 0;
makeRequest(myCallback)//function for API call
/*rest of the code*/
console.log("print second");
return valueToBeReturned;
}
function makeRequest(callback){
var xhttp = new XMLHttpRequest();
xhttp.open("GET", "my_url", true);
xhttp.send(null);
xhttp.onload = function() {
if(xhttp.readyState === 4) {
if(xhttp.status === 200) {
response = JSON.parse(xhttp.responseText);
callback(null, response);
}
}
}
}
function myCallback(data){
console.log("print first")
}
Now what happens is every time I run it, the entire code in the first function is executed and then the code in makeRequest is executed. I understand JS is synchronous in nature and everything. But I'm not able to get my work done here, which is fisrt it makes API call, then callback is executed, then the code after makeRequest. What am I doing wrong here?
PS this is not the actual code, just to demonstrate the flow of my program
You need to put callback as a parameter in makeRequest. I'm not sure what that null is there for, though. If you want "print second" to print second, you'll need to execute it after myCallback - maybe insert another callback?
function first_function(){
var valueToBeReturned = 0;
makeRequest(myCallback, restOfTheCode)
function restOfTheCode() {
/*rest of the code*/
console.log("print second");
}
}
function makeRequest(callback1, callback2){
var xhttp = new XMLHttpRequest();
xhttp.open("GET", "my_url", true);
xhttp.send(null);
xhttp.onload = function() {
if(xhttp.readyState === 4 && xhttp.status === 200) {
const response = JSON.parse(xhttp.responseText);
callback1(response);
callback2(response);
}
}
}
function myCallback(data){
console.log("print first");
}
But this whole thing would be a whole lot nicer if you used Fetch and Promises instead:
function makeRequest() {
return fetch('my_url')
.then(response => response.JSON())
}
// consume the request:
makeRequest()
.then(responseJSON => {
// do stuff with the responseJSON
});

Getting value from Ajax request in variable

I've this function.
function ajaxtakesource4(callback){
var ajaxRequest; // The variable that makes Ajax possible!
try{
ajaxRequest = new XMLHttpRequest();
} catch (e){
try{
ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try{
ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e){
alert("Your browser broke!");
return false;
}
}
}
// Create a function that will receive data sent from the server
ajaxRequest.onreadystatechange =function(){
if(ajaxRequest.readyState == 4 &&ajaxRequest.status==200){
var sourcetest = ajaxRequest.responseText;
callback(sourcetest);
}
}
ajaxRequest.open("POST", "takesource4.php", true);
ajaxRequest.send(null);
}
Also:
var somous4;
function run() {
ajaxtakesource4(function(sourcetest){
somous4=sourcetest;
});
alert(somous4);
}
and here I call the above the function:
<div id="run">
<button id="button_run" class="button" onclick="run()">Run</button>
</div>
When I click on the button it's supposed to alert response from Ajax request, but looks to be alerting a falsy value (undefined), as seen in this line:
alert(somous4);
I suggest you change the callback in the run function as follows:
var somous4;
function run() {
ajaxtakesource4(function(sourcetest){
somous4=sourcetest;
alert(somous4);
});
}
You're alerting somous4 before it's changed by the request callback. In this case the commands block executes first than the request callback.
Server-side languages as PHP does the work automatically, so you don't need to use events there. It sleeps while the request is not done. That's because the commands block turns the event callback.
Asynchronous code executes concurrently in nature. Thus, your alert statement may execute before your callback executes (callback will only after it receives back data from server). Put the alert inside the callback and it will show the value returned i.e.
var somous4;
function run() {
ajaxtakesource4(function(sourcetest){
somous4=sourcetest;
alert(somous4);
});
}
Edit: Based on OP's comment, instead of thinking about return values, do this:
function foo(soumous4) { // use somous4 for whatever you want... }
// Call this function foo inside the callback.
ajaxtakesource4(function(sourcetest){
somous4=sourcetest;
foo(somous4);
});

Making a function wait for done [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
Currently I have a function like this:
a: function (val) {
ajaxcall.done(function() {
console.log("Done");
}
}
I want to write another function which calls a, then wait until a is done (so the stuff inside the .done() executes, then it'll continue with the rest. Something like this:
console.log("beginning");
a("test");
console.log("End");
Would that print out
beginning
done
end
or would it sometimes be
beginning
end
done
depending on if the ajax calls take a long time?
That will always print:
beginning
End
Done
Even if the ajax call is instant, because JavaScript always completes the current execution thread before starting another one.
For the example you provided, it should print the done after the end
To wait for your function to end you can write something like that
a: function(val, done) {
ajaxcall.done(done)
}
//or if you want to do something before declaring it's done
a: function(val, done) {
ajaxcall.done(function() {
console.log('done');
done();
})
}
And afterwards use it like that
console.log("beginning");
a("test", function() {
console.log("End");
});
.done() can accept an array of functions to call
function ajaxcall() {
return new $.Deferred(function(d) {
setTimeout(function() {
d.resolve()
}, Math.random() * 3000)
}).promise()
}
function complete() {
console.log("End")
}
function a(val) {
ajaxcall().done([
function() {
console.log("Done");
},
complete
])
}
a()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Use the built in AJAX callback to call your function on complete.
function loadME() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
//if the data is downloaded and you receive no server errors,
if (xhttp.readyState == 4 && xhttp.status == 200) {
yourcallback();
}
};
xhttp.open("GET", "url for your query goes here", true);
xhttp.send();
}
Or in jQuery:
$.ajax({
url: "your api url here",
}).done(function() {
yourcallback();
});

How can I make XHR.onreadystatechange return its result?

I'm new to JavaScript programming. I'm now working on my Google Chrome Extension. This is the code that doesn't work... :P
I want getURLInfo function to return its JSON object, and want to put it into resp. Could someone please fix my code to get it work?
function getURLInfo(url)
{
var xhr = new XMLHttpRequest();
xhr.open
(
"GET",
"http://RESTfulAPI/info.json?url="
+ escape(url),
true
);
xhr.send();
xhr.onreadystatechange = function()
{
if (xhr.readyState == 4)
{
return JSON.parse(xhr.responseText);
}
}
}
var resp = getURLInfo("http://example.com/") // resp always returns undefined...
Thanks in advance.
You are dealing with an asynchronous function call here. Results are handled when they arrive, not when the function finishes running.
That's what callback functions are for. They are invoked when a result is available.
function get(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
// defensive check
if (typeof callback === "function") {
// apply() sets the meaning of "this" in the callback
callback.apply(xhr);
}
}
};
xhr.send();
}
// ----------------------------------------------------------------------------
var param = "http://example.com/"; /* do NOT use escape() */
var finalUrl = "http://RESTfulAPI/info.json?url=" + encodeURIComponent(param);
// get() completes immediately...
get(finalUrl,
// ...however, this callback is invoked AFTER the response arrives
function () {
// "this" is the XHR object here!
var resp = JSON.parse(this.responseText);
// now do something with resp
alert(resp);
}
);
Notes:
escape() has been deprecated since forever. Don not use it, it does not work correctly. Use encodeURIComponent().
You could make the send() call synchronous, by setting the async parameter of open() to false. This would result in your UI freezing while the request runs, and you don't want that.
There are many libraries that have been designed to make Ajax requests easy and versatile. I suggest using one of them.
You can't do it at all for asynchronous XHR calls. You cannot make JavaScript "wait" for the HTTP response from the server; all you can do is hand the runtime system a function to call (your handler), and it will call it. However, that call will come a long time after the code that set up the XHR has finished.
All is not lost, however, as that handler function can do anything. Whatever it is that you wanted to do with a return value you can do inside the handler (or from other functions called from inside the handler).
Thus in your example, you'd change things like this:
xhr.onreadystatechange = function()
{
if (xhr.readyState == 4)
{
var resp = JSON.parse(xhr.responseText);
//
// ... whatever you need to do with "resp" ...
//
}
}
}
For small edit talking about post: https://stackoverflow.com/a/5362513/4766489
...
if (typeof callback == "function") {
//var resp = xhr.responseText;
var resp = JSON.parse(xhr.responseText);
callback(resp);
}
...
And when you call
...
function(data) {
alert(data);
/* now do something with resp */
}
...

Ajax responseText comes back as undefined

I'm having problems with this piece of code; the return value comes back as 'undefined'. What's the problem?
var fx = null;
xmlhttp.open("GET", URL ,false);
xmlhttp.onreadystatechange=function()
{
alert("enter func");
if (xmlhttp.readyState==4)
{
if (xmlhttp.status == 200)
{
alert(fx);
fx = xmlhttp.responseText;
return fx;
}
else
{
alert("Error" + xmlhttp.statusText);
}
}
}
Newer code:
function getData(callback)
{
xmlhttp.open("GET", URL ,false);
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4)
{
if (xmlhttp.status == 200)
{
alert(xmlhttp.responseText);
cbfunc(xmlhttp.responseText);
}
else
{
alert("Error" + xmlhttp.statusText);
}
}
}
xmlhttp.send(null);
}
How I'm calling it:
getData( function cbfoo(txt)
{
//document.form.autodate.value=txt;
alert(txt);
alert(document.form.autodate.value);
});`
Update based on your edit
function getData(callback)
{
// you should move the creation of xmlhttp in here
// so you can make multiple getData calls if needed
// if you keep xmlhttp outside the function the different calls to getData will interfere
// with each other
xmlhttp.open("GET", URL ,false); // false should be true, to make it async
...
{
alert(xmlhttp.responseText);
cbfunc(xmlhttp.responseText); // your function gets passed as the
// parameter "callback" but you're
// using "cbfunc" here instead of "callback"
...
getData(function cbfoo(txt) // you can omit the function name here
...
Fixing those issues should make the code work.
Old answer
You're calling the XMLHttpRequest in Synchronous mode, that means that it will block the script until the request has finished, since you're assigning the onreadystatechange callback after the blocking call (that means after the request has already finished) your code never gets notified.
Since the synchronous mode blocks the script, it also blocks the Browser's UI, so it's not recommended to use this mode.
You should (for 99% of the cases) use the Asynchronous mode and use a callback to handle the data, since xmlhttp.open does not return the return value of the onreadystatechange callback, it simply returns undefined immediately when run in async mode.
Now a common pattern is to write a wrapper for the request and pass an anonymous function to this wrapper, which later will get called back when the request has finished.
function doRequest(url, callback) {
var xmlhttp = ....; // create a new request here
xmlhttp.open("GET", url, true); // for async
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4) {
if (xmlhttp.status == 200) {
// pass the response to the callback function
callback(null, xmlhttp.responseText);
} else {
// pass the error to the callback function
callback(xmlhttp.statusText);
}
}
}
xmlhttp.send(null);
}
You can now do a request and supply a function that will get called as soon as the request finishes, inside of that function you then do whatever you want to do with the response.
doRequest('http://mysite.com/foo', function(err, response) { // pass an anonymous function
if (err) {
alert('Error: ' + err);
} else {
alert('Response: ' + response);
}
});
This is the common programming model in the browser, always go with a asynchronous solution, if you block the script you block the whole Browser.

Categories