XMLHttpRequest response 'undefined' ... UNLESS alerting the variable 1st - browser

Bugger!
I am using an xmlhttprequest in javascript, calling a php page. The php page is only echoing a string.
When the xmlhttprequest hits 4 200, the response text is saved to a string. Also, the xmlhttprequest is in a function, and that function returns the response text.
THE ISSUE: the function is returning undefined, but I've circumvented the error by adding an alert(string). The alert then states 'undefined' and the function passes the echoed value on return, AS string!
With Opera, Chrome, Firefox, and Internet Explorer, only FF and IE populate the response text. Opera and Chrome don't work at all.
Code:
function xmlhttpr(help,type,address)
{
var string;
if ( help )
{
string = 'The xmlhttpr function:<br>params: (help,type,address)
<br>as<br>false/true,<br>get/post,<br>/addr.ess?h=elp';
return string;
}
if ( !address )
{
string = 'Parameter missing in xmlhttpr(0,type,address)';
return string;
}
if ( type == 0 )
{
type = 'GET';
}
if (type == 1 )
{
type = 'POST';
}
if ( window.XMLHttpRequest )
{
xmlhttp = new XMLHttpRequest();
}
else
{
xmlhttp = new ActiveXObject( "Microsoft.XMLHTTP" );
}
xmlhttp.onreadystatechange = function()
{
//alert(this.readyState + ' ' + this.status);
if ( this.readyState==4 && this.status==200 )
{
string = this.responseText;
}
}
xmlhttp.open( type , address , true );
xmlhttp.send();
alert(string); //STINKY
if ( string )
{
return string;
}
else
{
return 'Request failure';
}
}

XMLHttpRequest is also called AJAX and A stands for asynchronous, when you call .send() the request is issued to the server but the browser doesn't wait the request to finish, it jumps right to the next line which is alert(string) and because the request hasn't finished yet it's natural for it to be undefined.
All AJAX requests are asynchronous by nature which means the browser never waits for a request to finish before jumping to the next line after .send.
Now in your case it's hard to build your function so it's better to remove the function altogether and wherever you call that function instead just do the request and inside onreadystatechanged inside the if you have your string so do with it what you want to do (showing it to user , processing,whatever).
By the way there is synchronous XMLHttpRequest but it's deprecated and shouldn't be used because javascript code is naturally executed in one thread even UI code and you don't want to hang the buttons waiting for some request to server to finish.
So it worked in FF and IE ?!! it worked by coincidence because the request happened to finish and string happened to be populated.

Related

Chrome Plugin Manifest V3 - strange behavior of a promise function in popup.js

I'm trying to create a small plugin to make my day-to-day job easier. I have faced a very strange situation within the popup.js script. The promise function randomly refuses to get executed. I have spent some hours trying to debug or at least understand where the issue could be but without any results.
Here is the skeleton of the code:
document.addEventListener('DOMContentLoaded', function () {
// some initialization
document.getElementById("signinbutton").addEventListener("click", function(event) {
try {
// some more initialization
var user_email = '';
var advertiserId = '';
var checkibm = '';
user_email = $('#emailfield').val().trim();
advertiserId = $('#advertiseridfield').val().trim();
checkibm = $('#checkibm').is(':checked');
if (advertiserId && checkibm) {
_act = 'getTokenIdByAdvId',
_data = advertiserId
}
else if (advertiserId && !checkibm) {
_act = 'getTokenIdByAdvId',
_data = advertiserId
}
else if (user_email && validateEmail(user_email))
{
_act = 'getTokenIdByEmail',
_data = user_email
}
else
{
throw new Error("Valid input has not been provided");
}
sendMessagePromise({
act : 'getTokenIdByAdvId',
data: '16910'//encodeURIComponent(user_email)
})
.then(responseHandler)
.then(responseReplaceTokenHandler)
.then(show_ok('Done'))
.catch(failureCallback);
}
catch (error){
//doing some error catching here
});
});
The code above works perfectly. However, as soon as I fill in the real values in sendMessagePromise e.g
//_act and _data show the proper values when inspected
sendMessagePromise({
act : _act,
data: _data//encodeURIComponent(user_email)
})
the flow skips execution of sendMessagePromise and any other chained function, except the last one ".then(show_ok('Done'))", i.e the only result is the "Done" message on the screen.
I made sure the values are correct. I'm able to debug step-by-step and see the values being properly supplied. I have also put a bunch of console messages inside the chain promise functions to see where the execution gets stuck, but it seems like it doesn't even start executing sendMessagePromise.
As soon as I replace expression back to hardcoded values i.e
sendMessagePromise({
act : 'getTokenIdByAdvId',
data: '16910'//encodeURIComponent(user_email)
})
it starts working again. I'm really stuck and not sure how to debug or which steps to take further.
Please assist

various axios call relative at previous one

i have an array of variable number of urls and i must merge the data get with axion
the problem is then every axios call is relative to the data of the previus
if i have a fixed number of ulrs i can nest axion calls and live with that
i think to use something like this
var urls = ["xx", "xx", "xx"];
mergeData(urls);
function mergeData(myarray, myid = 0, mydata = "none") {
var myurl = "";
if (Array.isArray(mydata)) {
myurl = myarray[myid];
// do my stuff with data and modify the url
} else {
myurl = myarray[myid];
}
axios.get(myurl)
.then(response => {
// do my stuff and get the data i need and put on an array
if (myarray.length < myid) {
mergeData(myarray, myid + 1, data);
} else {
// show result on ui
}
})
.catch(error => {
console.log(error);
});
}
but i dont like it
there is another solution?
(be kind, i'm still learning ^^)
just to be clear
i need to optain
http request to "first url", parse the the json, save some data(some needed for the output)
another http request to "second url" with one or more parameter from previous data, parse the the json, save some data(some needed for the output)
... and so on, for 5 to 10 times
If your goal is to make subsequent HTTP calls based on information you get from previous calls, I'd utilize async/await and for...of to accomplish this instead of relying on a recursive solution.
async function mergeData(urls) {
const data = [];
for (const url of urls) {
const result = await axios.get(url).then(res => res.data);
console.log(`[${result.id}] ${result.title}`);
// here, do whatever you want to do with
// `result` to make your next call...
// for now, I am just going to append each
// item to `data` and return it at the end
data.push(result);
}
return data;
}
const items = [
"https://jsonplaceholder.typicode.com/posts/1",
"https://jsonplaceholder.typicode.com/posts/2",
"https://jsonplaceholder.typicode.com/posts/3"
];
console.log("fetching...")
mergeData(items)
.then(function(result) {
console.log("done!")
console.log("final result", result);
})
.catch(function(error) {
console.error(error);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.min.js"></script>
Using async/await allows you to utilize for...of which will wait for each call to resolve or reject before moving onto the next one.
To learn more about async/await and for...of, have a look here:
developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of
Hope this helps.

How to return a value from a function that uses 'http.get()' method in Node.js?

I have a simple HTTP GET function that only needs to return the response in a function, but right now this function is returning void.
The code in sitechecks.js
var checkSite = () => {
https.get('https://itmagazin.info', (res, err) => {
if (res.statusCode === 200 && res.statusMessage === 'OK') {
return `The site returned: ${res.statusMessage}`
} else return `Error, the site returned: ${err.message}`
})
}
module.exports = checkSite
And when I import the module in index.js, the console returns [Function: checkSite] and not the value itself.
// Index.js
var extSiteCheck = require('./sitechecks')
// This console prints [Function: checkSite] instead of "OK"
console.log(extSiteCheck.checkSite)
However, if I add the return statement on http.get() in the function, the console prints undefined. So I thought that this undefined is a progress, but I don't understand why does it return undefined?
(return http.get() in the checkSite function)
Any help, tips is appreciated.
Because callbacks in JavaScript are asynchronous, you can't return from within a callback.
That means this
console.log(extSiteCheck.checkSite)
runs before the request comes back.
You can try console logging within your callback (instead of trying to return a value), in order to see this in practice. But basically, whatever you are trying to achieve with the results of your get request, you need to do inside the callback.
mebbe something like ... console.log( extSiteCheck.checkSite() );

Node JS loop and callback

I'm using node-rest-client to make a GET call to an endpoint, and would like to make this call multiple times (in a loop), then expose a parameter of the response.
The code looks like:
// registering remote methods
client.registerMethod("reflect", "<the URL>", "GET");
// call the method
var i = 10;
while (i>0) {
client.methods.reflect(function (data, response) {
console.log("x-forwarded-for: " + data.headers["x-forwarded-for"]);
// raw response
//console.log(response);
});
i--;
}
The error I get is:
TypeError: Cannot read property 'x-forwarded-for' of undefined
If i is equal to 2, then this is OK.
I suppose the issue comes from the fact that this is asynchronous execution and all the calls in the while are fired at once, resulting into some clogging somewhere along the lines.
What is the best way of having a synchronous execution (assuming this is where the problem lies)?
First of all please check x-forwarded-for lies in response and if the same problem persists as you are expecting(asynchronous call) then
just wrap this call inside a anonymous function like this
while(i > 0) {
(function abc(){
client.methods.reflect(function (data, response) {
console.log("x-forwarded-for: " + data.headers["x-forwarded-for"]);
// raw response
//console.log(response);
});
}())
i--;
}

Javascript wait for request to process in a for loop

In my chrome extension i was checking for a function which can stop my for loop from processing till it gets a response from content scripts. Sharing the sample code below
function abc() {
chrome.tabs.query({'status': 'complete'}, function(tabArray) {
for (var i = 0, tab; tab = tabArray[i]; i++) {
var currentUrl = tab.url;
var tabId = tab.id;
if (currentUrl.match(otherthing)) {
chrome.tabs.sendRequest(tabId, {'type': 'getrequiredthing'},
function(response) {
if (response.isrequiredthind) {
callfunction(tabId);
}
}
);
}
}
});
}
Here when i get the matching url in else if i'm sending a request to the page for getting some info, if my info is positive i need to callfunction. But here in the for loop tabId is iterating very fastly and even if the response is positive it is calling the callfunction with next(or next) tabId.
Can you give your opinions on solving this keep waiting the for loop this response is received.
Thanks
The problem is that the third argument to sendRequest does not block on the request being ready. By design, JavaScript almost never blocks. This is a Good Thing. Instead, it uses an "event-driven" model.
Another problem is due to lexical scoping: When callfunction is called, tabId has the most recent value, not the value when sendRequest was called. To get around this, you need to create a separate scope for each loop iteration e.g.
for (...) {
var tabId = ...;
if (...) {
(function (localTabId) {
chrome.tabs.SendRequest(..., function (response) {
if (response.isrequiredthind) {
callfunction(localTabId);
}
}
})(tabId);
}
}

Resources