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

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
}
});
}

Related

Is there any way we can call another function after the ajax call completed?

Is there any way we can call another function after the ajax call completed?
I don't want to call it from success handler of ajax, as this ajax call is used in multiple areas, so it will be messy making switch from there?
Right now I am doing it in a bad way by using set timeout on this ajax call statement and executing next action within timeout.
problem:
function my_ajax(){
//ajax call goes here....
}
palce of calling:
my_ajax();
statement 1;
another place of calling:
my_ajax();
statement2;
any ideas?
Thanks
I'm assuming jQuery here as well, but you could wrap your ajax in a function.
function myAjax() {
return $.ajax(/* ... */)
}
const ajaxOne = myAjax();
ajaxOne.done(function() { /* do stuff one */ })
const ajaxTwo = myAjax();
ajaxTwo.done(functiion() { /* do stuff two */ })
edit
riffing off this a bit you could pass in your success/fail functions as callbacks
function myAjax(success, fail) {
const error = (fail !== undefined)
? fail
: function(err) { console.error(err) };
return $.ajax(/* ... */)
.done(success)
.fail(error);
}
You can use .always(), if your next call after ajax should be called all the time.
// Assign handlers immediately after making the request,
// and remember the jqXHR object for this request
var jqxhr = $.ajax( "example.php" )
.done(function() {
alert( "success" );
})
.fail(function() {
alert( "error" );
})
.always(function() {
alert( "complete" );
});
Source : http://api.jquery.com/jquery.ajax/
You can encapsulate your ajax with a function that accepts a callback as argument:
function my_ajax(callback) {
$.ajax('example.php').done(callback)
}
Then, you can call it with the callback you want:
// Will log 'AAA' on success of this request
my_ajax(function() { console.log('AAA') })
// Will log 'BBB' on success of this request
my_ajax(function() { console.log('BBB') })
So return the Ajax object back and use it to assign the custom done method.
function myAjax() {
return $.ajax( "fooPath" )
}
myAjax.done(function () { console.log(1) })
myAjax.done(function () { console.log(2) })
ajax is asynchronous, by default..
if i understand you need to wait the full response of one ajax, and use in other ajax...
with native jascript this type of work is some complex.... can be resolve with setInterval and clearInterval,
the idea
i worked in the past with globals vars.
setInterval, define a continous execution a customfunction, and return an id, to stop them in the future..... Now inside of your custom fuction then you define two condition, the first is stop clausses ( your first ajax is not complete ) and else ...execute the second ajax...and the clearInterval for stop continous execution
Of course jQuery provide and easy way to do this... is called ... "when"..
$.when( $.ajax( "test.php" ) ).then(function( data, textStatus, jqXHR ) {
// here ajax2
$.ajax( "test2.php" )
});

setInterval on a jQuery deferred object

I am trying to better understand the use of deferred objects in jQuery.
The getData method below fetches some data asynchronously. When done, it should be displayed to some predefined (log) section by addToChart. This should happen periodically, hence my using setInterval inside getData's done handler.
function getData() {
return $.ajax({
url: 'https://demo-live-data.highcharts.com/time-data.csv',
type: 'GET'
});
}
getData().done(addToChart, function() {
setInterval(getData, 1000);
});
function addToChart(data) {
document.getElementById('log').innerText += data;
}
$(document).ready(function() {
getData();
});
In above code, getData seems to get called only once. How do I let it be called periodically?
Also, is there any way to actually debug this code, rather than run it and scratch my head why it doesn't behave as expected? (I'm new to JavaSCript, in case you wonder). I stepped through the code using the Firefox debugger but that didn't help.
setTimeout is used to delay a function
https://www.w3schools.com/jsref/met_win_settimeout.asp
What you want to use is setInterval
https://www.w3schools.com/jsref/met_win_setinterval.asp
So looking at what you're trying to do, i would do it like this:
$(document).ready(function() {
function getData() {
$.ajax({
url: 'https://demo-live-data.highcharts.com/time-data.csv',
type: 'GET'
}).done(addToChart);
}
function addToChart(data) {
document.getElementById('log').innerText += data;
}
setInterval(getData, 1000);
});
You would need to do a while loop :
while (condition) {
code block to be executed
}
or the do/while loop :
do {
code block to be executed
}
while (condition);
Move the done inside the function so it will get called every time the function does and request succeeds
function getData() {
return $.ajax({
url: 'https://demo-live-data.highcharts.com/time-data.csv',
type: 'GET'
})
.then(addToChart)
.always(function() {
setTimeout(getData, 1000);
});
}
Alternate approach is wrap what you are currently doing in a new function
function getData() {
return $.ajax({
url: 'https://demo-live-data.highcharts.com/time-data.csv',
type: 'GET'
});
}
function loadChart() {
getData()
.then(addToChart)
.always(function() {
setTimeout(loadChart, 1000);
});
}
loadChart()

How do I extend JQuery's ajax done() method?

I have a jQuery ajax function like this:
jQuery.ajax({
url : '/blabla',
method : 'post',
data: {
bla : bla
}
}).done(function(data) {
// do lots of stuff
});
.. and I want to be able to add a check that the data passed into the done callback function doesn't have a session_timed_out value in it. Say I have many functions similar to the one above but they all do different things, but they ALL need to check if the session timed out first. Is there a proper way to extend done() so it initially checks for a timeout? I tried to do something like this but it failed:
var myAjax = function(options,callback){
var defaults = {
done: function(data){ //hijack the success handler?
if(check(data)){
callback(data);
}
}
};
jQuery.extend(options,defaults);
return jQuery.ajax(options);
}
When I use this extended function it works like before, meaning the check never gets called because it seems to be superseded by the done() callback in the actual implementation, which I guess makes sense. So I want to know if there is a way to "decorate" or extend done() function so it initially checks for the session timeout first. Or will I need to manually add this same session check to all of my ajax done's?
This snippet overrides the jQuery ajax method so you can add an extra check when it successfully returns.
(function($) {
var yourCustomCheck = function(ajaxRes) {
// Do whatever you need and return a boolean
};
var oldAjax = $.ajax;
$.ajax = function(opts) {
return $.Deferred(function() {
var _def = this;
oldAjax.call(this, opts).done(function(res) {
console.log("this is done first");
if(yourCustomCheck.call(this, res)) _def.resolve(res);
else _def.reject("timeout");
}).fail(function() {
_def.reject();
});
})
}
})(jQuery);
After this, you can use $.ajax() normally..
$.ajax({
.....
}).done(function(res) {
console.log("ok");
}).fail(function() {
console.log("no ok");
});
Here is a jsfiddle with a working example: https://jsfiddle.net/jormaechea/kffyo7qL/1/
You could chain a timeout checker:
jQuery.ajax({
url : '/blabla',
method : 'post',
data: {
bla : bla
}
}).then(timeoutCheck).then(function(data) {
// do lots of stuff
}, function(err) {
// handle error
});
function timeoutCheck(data) {
if (check(data)) {
return data;
} else {
// return a rejected promise to turn fulfilled into reject
return jQuery.Deferred.reject(new Error("timeout"));
}
}
Or, you could put this in your own ajax wrapper.
jQuery.ajaxT = function() {
return jQuery.ajax.apply(jQuery, arguments).then(timeoutCheck);
}
jQuery.ajaxT(...).then(function(results) {
// handle returned data here
// the timeoutCheck has already been done
}, function(err) {
// handle any errors here
});
Then, any ajax call you initiated with jQuery.ajaxT() would automatically have the timeoutCheck added to it's promise logic. If the ajax call succeeds and the timeout check passes, then the promise is fulfilled. If the ajax call succeeds and the timeout check fails, then the promise rejected.

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

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.

How to use jQuery ajax data to variable

I have the following javascript code:
function initSite(){
var site;
$.getJSON(www+'init/initSite', function(data) { site = data; });
}
$(document).ready(function(){
var site = initSite();
console.log(site);
}
which returns undefined... how can i store the json object that i recieve in the site variable so i can use it later?
EDIT:
This seem to work but im not sure if its correct to use this solution
var site = null;
$.ajax({
url: www+"init/initSite",
async: false,
dataType: 'json',
success: function (data) {
site = data;
}
});
console.log(site);
of course you got undefined because your function doesn't return anything and the ajax call is also asynchronous, so you have to wait the server response. Since $.ajax (and shortcuts) returns a promise you can do this task using deferred
function initSite(){
return $.getJSON(www+'init/initSite');
}
$(document).ready(function(){
$.when(initSite()).done(function(data) {
/* continue here the code execution, e.g. call another function */
doAllTheRemainingWorkWith(data)
});
}
as you can see this code is short and easy to read
function initSite(onSuccess){
$.getJSON(www+'init/initSite', onSuccess);
}
$(document).ready(function(){
initSite(function(data){
var site = data;
// initialize your code.
});
}
The problem is just a miss concept:
getJSON is an async call, and the site = data; will only happen way after the DOM is ready.
in order for you to make everything work the way it should, your initialization needs to start from your async call result and never before, for example:
// no need to wait for DOM ready to call `initSite`
initSite();
function initSite() {
$.getJSON(www+'init/initSite', function(data) {
initialization(data);
});
}
function initialization(site) {
// initialize all the things that need to be done
console.log(site);
}
$(document).ready(function(){
// do other stuff, for example show a loading message/image
}

Categories