Passing a return value - javascript

Please help, I have been looking at this all day and I know there must be a simple fix!
How do I pass results back to textService so that I can make a call such as
textResult = textService(text to pass in);
I don't want to use a global variable if I can avoid it.
This is the code
function textService(text){
req.open("GET", "http://....?text="+text, true);
req.onload = showResults;
req.send(null);
}
function showResults() {
results = req.responseXML.getElementsByTagName("Result");
}
Thank you in advance

function textService(text){
// set flag to false for sync requests
req.open("GET", "http://...?text="+text, false);
req.send(null);
// browser will be stalled till request is complete.
if(req.status == 200 && req.readyState == 4) {
return req.responseXML.getElementsByTagName("Result");
} else {
return 'request failed';
}
}
// javascript will stall till request is complete.
var results = textService('someText');
Note, making synchronous request can be harmful, if a request fails, it might stall the browser indefinatly. It's better to do it asynchronously.
function textService(text, callback){
// async is true by default, no need to pass 3rd param.
req.open("GET", "http://...?text="+text);
req.send(null);
req.onreadystatechange = function(){
if(this.readyState == 4 || this.status == 200) {
callback(this.responseXML);
}
}
}
textService('someText', function(xml){
// do stuff with XML.
});
Just need switch your coding mind to async programming ;)

You can use this
function showResults() {
results = this.responseXML.getElementsByTagName("Result");
}

Related

How to separate XMLHttpRequest from the main function for better visbility/testibility (without Promises / asnyc/await )

Imagine this function:
function myMainFunction() {
doSomeInitialStuff();
// more stuff..
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == XMLHttpRequest.DONE) {
// Now that we know we received the result, we can do the heavy lifting here
if (xhr.status == 200) {
console.log("ready 200");
let result = JSON.parse(xhr.responseText);
doStuff(result);
// and much more stuff..
} else {
console.log("error", xhr.status);
return undefined;
}
}
};
xhr.open("GET", "http://example.com", true);
xhr.send(null);
}
This works fine, but it is impossible to test, and this function has become a monster.
So I'd like to refactor it, by separating all the different parts in their own unique functions.
The problem is, I do not know how to extract the XHR part and still keep it working.
I cannot use Promises nor asnyc/await and have to stick to using plain XHR.
What I'd normally do is to create a seperate async function for the ajax call (or the xhr in this case). Simply await it's result and go from there. Easy to separate. But I do not have the luxury of await or anything this time.
What I am trying to get at is something like this
function refactoredMyMainFunction() {
doSomeInitialStuff();
// more stuff..
let result = xhrFunction();
doStuff(result); // result would be undefined here, since I cannot wait for the xhr request to finish.
}
You can implement a callback-based API:
function myMainFunction() {
doSomeInitialStuff();
// more stuff..
xhrFunction(doStuff);
}
function xhrFunction(cb) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == XMLHttpRequest.DONE) {
// Now that we know we received the result, we can do the heavy lifting here
if (xhr.status == 200) {
console.log("ready 200");
let result = JSON.parse(xhr.responseText);
cb(result);
// and much more stuff..
} else {
console.log("error", xhr.status);
return undefined;
}
}
};
xhr.open("GET", "http://example.com", true);
xhr.send(null);
}

How to stop weblistener after the callback associated has been executed?

I want to execute a function (named callback in this context) with a weblistener in Javascript. When the listener detect the good pattern it calls the callback function and this function never stop...
All of this is done with browser.webRequest.onBeforeRequest.addListener
The weblistener with browser.webRequest.onBeforeRequest.addListener() detects the good pattern, call the associated function which make a GET request. Once it's done, the GET request is done again and again
function getResponseFromSP()
{
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4 && xmlHttp.status == 200){
console.log(xmlHttp.response);
browser.webRequest.onBeforeRequest.removeListener(getResponseFromSP);
if(!browser.webRequest.onBeforeRequest.hasListener(getResponseFromSP)){
browser.webRequest.onBeforeRequest.addListener(
getResponseFromSP,
{urls: ["https://example.com/policy"]}
);
}
}
}
xmlHttp.open("GET", "https://example.com:5000/policy", true); // true for asynchronous
xmlHttp.responseType = 'json';
xmlHttp.send(null);
}
/*
Main part
*/
browser.webRequest.onBeforeRequest.addListener(
getResponseFromSP,
{urls: ["https://example.com/policy"]}
);
One common solution is to create a variable in the appropriate scope, check that it's false when you want to execute the function, but set it to true after execution.
var isDone = false;
// ...
if(!isDone) {
// ... execute the function on the event being listened for here, then set
isDone = true;
}

Having trouble with ASYNC AJAX CALLBACK

There are about a million posts on SO about async callbacks, but I cannot figure out how to get mine to work
I have an AJAX request:
function checkName();
var ajax = new XMLHttpRequest();
ajax.open("POST", "index.php", true); // true = async
ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
ajax.onreadystatechange = function(){
if(ajax.readyState == 4 && ajax.status == 200){
var pass = ajax.responseText + 0;
}
}
ajax.send("emailcheck="+email);
return pass;
}
The only possible outcomes for pass are 1 or 0.
I've tried moving the return immediately after the assignment of pass, but still nothing. That's when I started looking around on here and found callbacks, but I'm having trouble figuring out how to do it.
What I would like to do is have something like:
if(checkName()){
// Do stuff
}else{}
I don't want to do a synchronous ajax request (i.e. false for third param), because that stops an animation I have and also prevents the user from performing other tasks on the site for the short time the call takes place.
I know this is very similar to other posts about the topic, I just can't quite figure it out.
Thank you in advance.
Only with a synchronous call you can implement this. And no one would want that. You said it yourself.
if(checkName()){
// Do stuff
}else{}
You need to use a callback function indeed. See this example:
function checkName(callBack) {
var ajax = new XMLHttpRequest();
ajax.open("POST", "index.php", true); // true = async
if (callBack)
{
ajax.callBack = callBack;
}
ajax.onreadystatechange = function(){
if(this.readyState == 4 && this.status == 200){
if (this.callBack)
{
this.callBack(this.responseText);
}
}
}
ajax.send("emailcheck="+email);
}
function checkNameFinish(data)
{
alert(data);
}
checkName(checkNameFinish);
checkName now accepts an argument callBack. This has to be a function. When the readystate completes it checks if there's a callBack set. If so then execute the callBack function and pass the response as argument.

javascript: wait for a return

I have this problem.
I have a function for example called functionA() that needs the results from another function called functionB().
var globalVar="";
function functionA(){
//...
functionB();
//here i have to use the global variable (that is empty because functionB isn't finished)
}
function functionB(){
//ajax request
globalVar=ajaxRequest.responseText;
}
How can I do to let the functionB finish befor continue with the execution of functionA?
Thanks!
This is the code:
var ingredientiEsistenti="";
function ShowInserisciCommerciale() {
getElementiEsistenti();
JSON.parse(ingredientiEsistenti);
}
function getElementiEsistenti(){
// prendo gli ingredienti esistenti.
var url = "http://127.0.0.1:8080/Tesi/Ingredienti";
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("POST", url, false);
xmlHttp.send(null);
xmlHttp.setRequestHeader("Content-type",
"application/x-www-form-urlencoded");
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4) // COMPLETED
{
if (xmlHttp.status == 200) // SUCCESSFUL
{
ingredientiEsistenti = xmlHttp.responseText;
} else {
alert("An error occurred while communicating with login server.");
}
}
};
}
You've got one of many options, that don't require an evil global variable:
Move the code you want to see executed to the onreadystatechange callback of the ajax request, that way, it won't get executed until you received a response
Redefine functionA, so that it takes a parameter that allows you to skip the first bit:
Make the request synchronous, not recommended, though
use a timeout/interval to check the readystate of the request manually (brute-force, not recommended either)
Perhaps there is some worker trickery that could do the trick, too, in your particular case
function functionA(skipDown)
{
skipDown = skipDown || false;
if (skipDown === false)
{
//doStuff
return functionB();//<-- call functionA(true); from the readystatechange callback
}
//this code will only be called if skipDown was passed
}
It is impossible to have a sleep/wait in JavaScript when the call is asynchronous. You need to use a callback pattern to make this action occur.
It is possible to make an XMLHttpRequest synchronous, but that can lead to other problems. It can hang the browser as it blocks all other actions from happening. So if you want to show a loading animation, it most likely will not execute.
You can make your AJAX request synchronous. https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Synchronous_and_Asynchronous_Requests
var request = new XMLHttpRequest();
// Last parameter makes it not asnychronous
request.open('GET', 'http://www.mozilla.org/', false);
request.send(null);
// Won't get here until the network call finishes
if (request.status === 200) {
console.log(request.responseText);
}
However, that will block the UI while waiting for the server to respond, which is almost never what you want. In that case, you should use a callback to process results.
Here's an example using a callback without relying on a global variable. You should always run away from those
function ShowInserisciCommerciale( ) {
getElementiEsistenti(function(responseText) {
JSON.parse(responseText);
});
}
function getElementiEsistenti(successCallback){
var url = "http://127.0.0.1:8080/Tesi/Ingredienti";
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("POST", url, false);
xmlHttp.send(null);
xmlHttp.setRequestHeader("Content-type",
"application/x-www-form-urlencoded");
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4) // COMPLETED
{
if (xmlHttp.status == 200) // SUCCESSFUL
{
successCallback(xmlHttp.responseText);
} else {
alert("An error occurred while communicating with login server.");
}
}
};
}

How do I make Ajax calls at intervals without overlap?

I'm looking to setup a web page that samples data via AJAX calls from an embedded web-server. How would I set up the code so that one request doesn't overlap another?
I should mention I have very little JavaScript experience and also a compelling reason not to use external libraries of any size bigger than maybe 10 or so kilobytes.
You may want to consider the option of relaunching your AJAX request ONLY after a successful response from the previous AJAX call.
function autoUpdate()
{
var ajaxConnection = new Ext.data.Connection();
ajaxConnection.request(
{
method: 'GET',
url: '/web-service/',
success: function(response)
{
// Add your logic here for a successful AJAX response.
// ...
// ...
// Relaunch the autoUpdate() function in 5 seconds.
setTimeout(autoUpdate, 5000);
}
}
}
This example uses ExtJS, but you could very easily use just XMLHttpRequest.
NOTE: If you must have an exact interval of x seconds, you would have to keep track of the time passed from when the AJAX request was launched up to the setTimeout() call, and then subtract this timespan from the delay. Otherwise, the interval time in the above example will vary with the network latency and with the time to processes the web service logic.
I suggest you use a small toolkit like jx.js (source). You can find it here: http://www.openjs.com/scripts/jx/ (less than 1k minified)
To setup a request:
jx.load('somepage.php', function(data){
alert(data); // Do what you want with the 'data' variable.
});
To set it up on an interval you can use setInterval and a variable to store whether or not a request is currently occuring - if it is, we simple do nothing:
var activeRequest = false;
setInterval(function(){
if (!activeRequest) {
// Only runs if no request is currently occuring:
jx.load('somepage.php', function(data){
activeRequest = false;
alert(data); // Do what you want with the 'data' variable.
});
}
activeRequest = true;
}, 5000); // Every five seconds
AJAX, despite the name, need not be asynchronous.
Here is the asynchronous method...
var req;
function ajax(method,url,payload,action)
{
if (window.XMLHttpRequest)
{
req = new XMLHttpRequest();
req.onreadystatechange = action;
req.open(method, url, true);
req.send(payload);
}
else if (window.ActiveXObject)
{
req = new ActiveXObject("Microsoft.XMLHTTP");
if (req)
{
req.onreadystatechange = action;
req.open(method, url, true);
req.send(payload);
}
else
{
alert("Could not create ActiveXObject(Microsoft.XMLHTTP)");
}
}
}
...but here is a synchronous equivalent...
function sjax(method,url,payload,action)
{
if (window.XMLHttpRequest)
{
req = new XMLHttpRequest();
req.open(method, url, false);
req.send(payload);
action();
}
else if (window.ActiveXObject)
{
req = new ActiveXObject("Microsoft.XMLHTTP");
if (req)
{
req.onreadystatechange = action;
req.open(method, url, false);
req.send(payload);
}
else
{
alert("Could not create ActiveXObject(Microsoft.XMLHTTP)");
}
}
}
... and here is a typical action ...
function insertHtml(target)
{
var pageTarget = arguments[0];
if (req.readyState == 4) // 4 == "loaded"
{
if (req.status == 200) // 200 == "Ok"
{
if (req.responseText.indexOf("error") >= 0)
{
alert("Please report the following error...");
pretty = req.responseText.substring(req.responseText.indexOf("error"),1200);
pretty = pretty.substring(0,pretty.indexOf("\""));
alert(pretty + "\n\n" + req.responseText.substring(0,1200));
}
else
{
div = document.getElementById(pageTarget);
div.innerHTML = req.responseText;
dimOff();
}
}
else
{
alert("Could not retreive URL:\n" + req.statusText);
}
}
}

Categories

Resources