node js : should be use alert to invoke the function? - javascript

i dont know what happen with my code..i have a Node.js that queries a MySQL db within the route and displays the result to the user. My problem is how do I run the queries and block until queries are done before redirecting the user to the page they requested?
if i add alert before call,function run normally and quick response..but if alert disable the function cant return any value,the function like freeze..
this user code to request value to nodejs
function fred(){ //request function from here to fblue
alert('fred called'); //if i disable alert,the function not return any value
get('id', function(datmovMar) {
var obj = JSON.parse(datmovMar);
var items = Object.keys(obj);
var output='';
items.forEach(function(item) {
output+=obj[item].something+'<br/>';
alert(output);
});
});
}
function get(id, callback) {
$.ajax('http://localhost:8000/' + id + '/', {
type: 'GET',
dataType: 'json',
success: function(data) { if ( callback ) callback(data); },
error : function() { if ( callback ) callback(null); }
});
}
and this code locate in node js
fblue(function(datmovMar){ //call function from here
res.write(JSON.stringify(datmovMar));
res.end('\n');
});
function fblue(callback){
var query = connection.query('SELECT something from table'),
pinMarker = [];
query
.on('error', function(err) {
console.log( err );
updateSockets( err );
})
.on('result', function( user ) {
pinMarker.push( user );
})
.on('end',function(){
if(connectionsArray.length) {
jsonStringx = JSON.stringify( pinMarker );
callback(jsonStringx);
}
});
}
i dont know why if alert disable the function cant run normally?
please help...
thanks

You're calling jQuery's $.ajax method which will create an asynchronous javascript request to your server.
This means that the control flow will continue right after you initiated the call to your server.
So you should not expect from fred() function to block until your request has been served, instead you need to rewrite your browser side javascript code in asynchronous way.

jQuery's $.ajax function by default runs asynchronously. That means the request won't be blocked while it's running, so subsequent lines of code will be immediately executed. With async calls, order of execution is not guaranteed.
You can 'cheat' a little bit here and specify the async option as follows:
$.ajax('http://localhost:8000/' + id + '/', {
type: 'GET',
dataType: 'json',
async: false,
success: function(data) { if ( callback ) callback(data); },
error : function() { if ( callback ) callback(null); }
});
That will force the $.ajax call to NOT return until it is completed. That's not really the JavaScript way of doing things, however, because you lose the efficiencies gained by asynchronous execution. As another KARASZI pointed out, you should write this asynchonously.

Related

setting and calling global var using ajax

I have a function that goes to a PHP script which returns the Server Operating System.
The script is literally dead simple:
<?php
echo (strpos(PHP_OS, 'Linux') > -1 ? 'Lin' : 'Win');
My goal is to be able to differentiate between operating systems so that I can declare a global path variable in my .js file for future uses.
This is what I've done so far:
function serverOS()
{
var os;
$.ajax({
url: '../scripts/ajax/detect-os.php',
type: 'get',
success: function(res)
{
os = res;
return os;
},
error: function(res) {alert('Major Error!'); console.log(res)}
});
return os;
}
console.log(serverOS());
The ending console.log outputs undefined - but if I console.log os inside of the success callback function, then it outputs what I expect.
According to this: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var
I should be able to do what I want with the above script but it doesn't seem to work. How do I go about setting and getting a global variable using ajax in JavaScript/jQuery?
AJAX operations are asynchronous. They will not block the rest of your JavaScript from executing.
The final return statement in your function attempts to return os immediately (before the AJAX operation has completed. Remove that return statement and in the success handler take care of all the logic to get the value back to the caller.
function serverOS() {
// The AJAX method will invoke the logging function no matter what.
// But, it won't happen until the AJAX call is complete.
$.ajax({
url: '../scripts/ajax/detect-os.php',
type: 'get',
success: function(res) {
returnValue(res);
},
error: function(res) {
alert('Major Error!');
returnValue(res);
}
});
}
function returnValue(val){
console.log(val);
}
serverOS();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Scott's Answer definitely works - but there does also seem to be an alternative I stumbled across. There's an AJAX property called async. Setting this to false in my function means it becomes a synchronous ajax call. Changing my function to this:
var os;
function serverOS()
{
$.ajax({
url: '../scripts/ajax/detect-os.php',
type: 'get',
async: false,
success: function(res)
{
returnValue(res)
},
error: function(res)
{
alert('Major Error!');
returnValue(res)
}
});
}
function returnValue(val)
{
os = val;
return os;
}
serverOS();
console.log(os); //this print Lin on my Linux machine.
ref: https://api.jquery.com/jQuery.ajax/

How to execute a Javascript function after another has completed using promises?

I wish to refresh the page after values have been saved to a database, using js promises.
My code is wrapped inside a jQuery event listener:
$("img[class=okButton]").click(function(){
var field_userid = $(this).attr("id");
doThisFirst();
// then make a promise
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
wait(500).then(() => writeNewRoom(field_userid)); // function to write to database
refreshPage(); // after write has finished
});
///////////////////
function writeNewRoom(field_userid)){
// ajax to do something;
}
///////////////////
function refreshPage(){
if(window.confirm("Click to refresh")){location = location}
}
The intended behaviour is to process data first, then finish "doing something" in the writeNewRoom() function before refreshing the page in the refreshPage() function.
What is actually happening is that the first doThisFirst() function is processed correctly, but then the window.confirm box in the third function, pops up BEFORE the writeNewRoom function has run.
I've never used promises before, so can anyone help figure out what went wrong? I took the basic syntax from the mozilla website: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises
Any help is much appreciated.
In your case, you would want to put a call back in your writeNewRoom() method.
For example, you call whatever you need to do on the .click() function and put a .done() method when your ajax call for writing to the database is done.
$("img[class=okButton]").click(function(){
var field_userid = $(this).attr("id");
doThisFirst();
// Remove the Promise
writeNewRoom(field_userid); // function to write to database
});
function writeNewRoom(field_userId) {
$.ajax({
url: "/someurl",
method: "method",
data: {
a: field_userId
}
}).done(function(data) {
console.log('success', data)
refreshPage(); // This is where you refresh the page.
}).fail(function(xhr) {
console.log('error', xhr);
});
}
If your // ajax to do something; returns a promise (jQuery.ajax() does) you can do it like this:
wait(500).then(() => writeNewRoom(field_userid))
.then(() => refreshPage());
There's also one extra parenthesis here function writeNewRoom(field_userid))
if the writeNewRoom(field_userid) is doing an ajax call, you put the refreshPage()-function into the callback of the ajax call, so it is executed AFTER the ajax has finished, e.g:
function writeNewRoom(field_userid)){
$.ajax({
url: "someUrl",
type: 'GET',
success: (result) => {
refreshPage() //when ajax has succeded, refresh page
},
error: (err) => {
//do something else
}
});
}

Recursive function in javascript and ajax

I'm trying to do a little web in JavaScript + Ajax and I want to do it recursively. I've never used ajax before and the problem is I don't know to finish functions. The code looks like that:
var cont = 0;
var function1 = function (query) {
$.ajax({
url: '...',
data: {
.
.
.
},
success: function (response) {
instructions;
function2(param1, param2);
}
});
};
var function2 = function (query, param2) {
$.ajax({
url: '...',
data: {
.
.
.
},
success: function (response) {
instructions;
function3(param1, param2, param3);
}
});
};
var function3 = function (query, param2, param3) {
if (cont == 2) {
console.log("finish");
return;
}
var test = $.ajax({
url: '...',
data: {
.
.
.
},
success: function (response) {
if (...) {
cont++;
instructions;
var audio = new Audio(...);
audio.play();
audio.onended = function () {
instructions;
function3(query, param2, param3);
return;
};
} else {
instructions;
function3(query, param2, param3);
};
return;
}
});
return;
};
document.getElementById('search-form').addEventListener('submit', function (e) {
e.preventDefault();
function1(document.getElementById('query').value);
}, false);
So basically, when cont == 2I try to get out of javascript function3 with return; but some part of the program ( I don't know if the success: function (response) or the full javascript function3 ) is still running and instructions are being executed.
How could I solve this?
First off, the way to do this properly is to make use of jQuery's deferred objects.
As you have probably noticed, the program doesn't simply wait at the ajax request, and then proceed to the 'success' handler. This is because Javascript uses a non-blocking/waiting model. So you call $.ajax({params,...}), this sends the request, but whatever's after this will then immediately run, without waiting. Then, once the top level function has finished executing and nothing else is running, the response can be processed, and the 'success' handler is invoked.
So how to do this stuff properly? Start by arranging your request functions like this:
function doRequest1() {
return $.ajax({
url: '...',
data: {
.
.
.
}
});
}
function doRequest2(parameter) {
return $.ajax({
url: '...',
data: {
.
p: parameter
.
}
});
}
Notice that we aren't providing a success handler, but we are returning the value that $.ajax returns. This is a deferred object which is used to represent a request which has been sent, but for which a response hasn't been received/handled. You can attach a handler to the object like this:
var r1 = doRequest1();
r1.then(function() {
// Do stuff on success...
});
A nice thing about these objects is that they can be chained using 'then'.
'then' accepts a function which takes the value of the old request and produces a new request to do next:
var allRequests = doRequest1().then(function(result1) {
return doRequest2("hello");
});
The 'allRequests' variable is now a deferred object representing the result of doRequest2. How do you get this result? You use 'then()', just like any other deferred:
allRequests.then(function(result) {
alert("All requests completed. Result of last one: " + result);
});
Make sure that you understand how the result from 1 request can be used to set the parameters for the next one, or even decide which request to make next.
If you don't need one request's result to determine the next, rather, you just want to run a number of requests and wait for them all to complete, you can use a shortcut, 'when':
$.when(doRequest1(),doRequest2(), doRequest3()).then(function(result1,result2,result3) {
// All done
});
Another nice thing about deferreds is that they can be cancelled:
allRequests.abort();
Using the above, hopefully you can see how to restructure your code so you get a sequence of requests with a function to run after all 3 have completed.
Watch the value of your global variable cont through the flow of your program. It may be that it is (never) equal to 2 when function3() is called and that is why your program continues.

How to await the ajax request?

I am trying to write a JS code that will cancel the "btn_submit" buttons .onclick event if the given number already exists in the database. I use AJAX to query the DB for the given number and to determine if the should send the data to a .php site which will upload the question. To determine this I need the numOfRows variable's value, but because I set it in AJAX it will stay on 0. The validation() function will finish before my AJAX query finishes and this causes the problem that will always state that the given number does not exist in the DB (numOfRows will always stay on 0).
How can I await the AJAX query's finish before I compare the numOfRows to 0 in my validation() function's ending lines? If the number already exists in the DB, I need to return false to this line:
document.getElementById("btn_submit").onclick = validation;
Thank you!
var textAreaList;
var numOfRows = 0;
var finished = false;
document.getElementById("btn_submit").onclick = validation;
textAreaList = document.getElementsByClassName("text_input");
function validation() {
loadNumRows();
try {
document.getElementById('failure').hidden = true;
}
catch(e) {
console.log(e.message);
}
textAreaList = document.getElementsByClassName("text_input");
var failValidation = false;
for (var i = 0; i < textAreaList.length; i++) {
console.log(textAreaList[i]);
if (textAreaList[i].value == "") {
textAreaList[i].style.border = "2px solid #ff0000";
failValidation = true;
} else {
textAreaList[i].style.border = "2px solid #286C2B";
}
}
return !(failValidation || numOfRows != 0);
}
function loadNumRows(){
$.ajax({
url: 'php/SeeIfNumberExists?number=' + document.getElementById('number_inp').value,
type: "GET",
cache: false,
success: function (html) {
numOfRows = parseInt(html);
}
});
}
use of async/await with a transpilers like Babel to get it working in older browsers. You’ll also have to install this Babel preset and polyfill from npm:
npm i -D babel-preset-env babel-polyfill
Then
function getData(ajaxurl) {
return $.ajax({
url: ajaxurl,
type: 'GET',
});
};
async function test() {
try {
const res = await getData('https://api.icndb.com/jokes/random')
console.log(res)
} catch(err) {
console.log(err);
}
}
test();
or the .then callback is just another way to write the same logic.
getData(ajaxurl).then((res) => {
console.log(res)
});
Using async: false is an extremely bad idea, and defeats the whole purpose of using AJAX at the first place — AJAX is meant to be asynchronous. If you want to wait for a response from your script when you make the AJAX call, simply use deferred objects and promises:
var validation = function () {
var numberCheck = $.ajax({
url: 'php/SeeIfNumberExists?number=' + $('#number_inp').val(),
type: "GET"
});
// Listen to AJAX completion
numberCheck.done(function(html) {
var numOfRows = parseInt(html),
textAreaList = $('.text_input'),
finished = false;
// Rest of your code starts here
try {
document.getElementById('failure').hidden = true;
}
catch(e) {
console.log(e.message);
}
// ... and the rest
});
}
// Bind events using jQuery
$('#btn_submit').click(validation);
I see in your code that you are using a mixture of both native JS and jQuery — it helps if you stick to one :)
Never use async:false its dangerous, your app might misbehave.
You can use await only when your response returns a promise.
Unfortunately jQuery ajax doesn't return Promise when its completed.
But you can use promise in ajax request and return the promise when its done.
function asyncAjax(url){
return new Promise(function(resolve, reject) {
$.ajax({
url: url,
type: "GET",
dataType: "json",
beforeSend: function() {
},
success: function(data) {
resolve(data) // Resolve promise and when success
},
error: function(err) {
reject(err) // Reject the promise and go to catch()
}
});
});
}
We have converted ajax call into promise so now we can use await.
try{
const result = await asyncAjax('your url');
} catch(e){
console.log(e);
}
this works for me
async function doAjax() {
const result = await $.ajax({
url: "https://api.exchangerate-api.com/v4/latest/USD",
type: 'GET',
});
return result;
}
async function tt(){
var res = await doAjax()
var money = res.rates.INR
console.log(money)
}
tt()
(I acknowledge this is not the best way to go about things, but this is the quickest way to get your code working as is. Really though, you should rethink how you are pulling the numOfRows value so that it will work with truly asynchronous Ajax. All that being said...):
Start by setting async : false in the $.ajax call. The A in Ajax stands for asynchronous. That means, execution continues rather than waiting for it to return. You want to turn that off (i.e. make it synchronous). Actually, that should be the whole solution given the code you have there.
$.ajax({
url: 'php/SeeIfNumberExists?number=' + document.getElementById('number_inp').value,
type: "GET",
async: false,
cache: false,
success: function (html) {
numOfRows = parseInt(html);
}
});
One caveat from the docs for $.ajax:
Cross-domain requests and dataType: "jsonp" requests do not support synchronous operation. Note that synchronous requests may temporarily lock the browser, disabling any actions while the request is active. As of jQuery 1.8, the use of async: false with jqXHR ($.Deferred) is deprecated; you must use the success/error/complete callback options instead of the corresponding methods of the jqXHR object such as jqXHR.done() or the deprecated jqXHR.success().

Wait for AJAX to finish before proceeding with the loop?

Why is it that whenever I put an ajax inside a for loop, it doesn't synchronize well?
like for example, my code is:
function addToUserGroupList() {
_root.qDomId('js-assignGroupArrBtn').disabled = true
for (var i = 0; i < selectedIds.length; i++) {
$.ajax({
type: "POST",
url: 'groupManage.ashx',
dataType: 'text',
data: 'type=getInfo&groupId=' + selectedIds[i],
success: function (result) {
if (result != '') {
this.groupName = result.split('&')[0];
this.groupNotes = result.split('&')[2];
userGroupList.push({ 'uid': parseInt(selectedIds[i]),
'name': this.groupName,
'adminStr': this.groupNotes
});
_root.userListObj.gourpInst.gourpTB(userGroupList);
}
},
error: function (XMLHttpRequest, status, errorThrown) {
alert('failed to add to user\'s group.');
}
});
}
_root.qDomId('js-assignGroupArrBtn').disabled = false;
selectedIds = [];
}
Why is that it calls out selectedIds = []; first before the Ajax Query?
Is it possible to let the ajax queries be finished before proceding to selectedIds = [];? Because it clears the array right before it's finished doing the stuffs. :/
First off, you really need to understand how an Ajax call is Asynchronous (that's what the "A" in Ajax stands for). That means that calling $.ajax() only starts the ajax call (it sends the request to the server) and the rest of your code happily continues running. Sometimes LATER after the rest of your code has executed, the success or error callback handler is called when the response comes back from the server. This is NOT sequential programming and must be approached differently.
The #1 thing this means is that ANYTHING that you want to have happen after the ajax call MUST be in the success or error handler or called from there. Code located right after the ajax call will be run long before the ajax call completes.
So, there are different ways to structure your code to work with this asynchronous concept. If you only want one asynchronous ajax call in flight at a time, you have to do this restructuring and can't use a simple for loop. Instead, you can create an index variable and in the completion function, increment the index and kick off the next iteration. Here's one way to code it:
function addToUserGroupList() {
_root.qDomId('js-assignGroupArrBtn').disabled = true
var i = 0;
function next() {
if (i < selectIds.length) {
$.ajax({
type: "POST",
url: 'groupManage.ashx',
dataType: 'text',
data: 'type=getInfo&groupId=' + selectedIds[i],
success: function (result) {
i++;
if (result != '') {
this.groupName = result.split('&')[0];
this.groupNotes = result.split('&')[2];
userGroupList.push({ 'uid': parseInt(selectedIds[i]),
'name': this.groupName,
'adminStr': this.groupNotes
});
_root.userListObj.gourpInst.gourpTB(userGroupList);
}
next();
},
error: function (XMLHttpRequest, status, errorThrown) {
alert('failed to add to user\'s group.');
}
});
} else {
// last one done
_root.qDomId('js-assignGroupArrBtn').disabled = false;
selectedIds = [];
}
}
// kick off the first one
next();
}

Categories