I feel like this is really easy, but I can not figure it out.
I want to set the currentUserId inside of the getCurrentUser function, which I would like to be able to call inside other functions.
Below is what I have now, and it returns undefined. What am I missing?
var currentUserId;
function getCurrentUser() {
$.ajax({
type: "GET",
url: '/set_user',
success: function(result) {
currentUserId = result.id;
return currentUserId;
},
error: function(err) {
console.log(err);
}
})
};
getCurrentUser();
console.log("current user id is " + currentUserId);
This happens because inside getCurrentUser method you are doing an asynchronous AJAX call, so the value is not yet ready when you print it with console.log.
The value will be correctly set when the GET /set_user request will end successfully, only in that case the function:
success: function(result) {
currentUserId = result.id;
return currentUserId;
}
will be executed and currentUserId will be set.
Based on jQuery.ajax() documentation, the value returned by $.ajax call is a Promise. So first, return the promise to the caller (1) and then wait the promise is resolved to print the value (2).
var currentUserId;
function getCurrentUser() {
return $.ajax({ // 1. Return the Promise here
type: "GET",
url: '/set_user',
success: function(result) {
currentUserId = result.id;
return currentUserId;
},
error: function(err) {
console.log(err);
}
})
};
// 2. Then wait the call to succeed before print the value (use the 'done' method)
getCurrentUser().done(function() {
console.log("current user id is " + currentUserId);
});
Like Andrea explain, the value was not ready yet when you make a ajax call.
One way to avoid this is use callback:
function getCurrentUser(callback) {
$.ajax({
type: "GET",
url: '/set_user',
success: function(result) {
var currentUserId = result.id;
if (callback)
callback(currentUserId);
},
error: function(err) {
console.log(err);
}
})
};
function displayResult(userId){
console.log("current user id is " + userId);
}
getCurrentUser(displayResult);
And this will also avoid the use of globe variable currentUserId.
Related
I'm having some trouble. I'm trying to execute my ajax function 1 by 1, not all at the same time. I'm using promise but I have no more idea on how to achieve it. Here is my code :
function run_action(action){
if(action == "login"){
return $.ajax({
url: "login.php",
type: "post",
data: {password: password},
beforeSend: function() {
console.log('beforeSend login');
},
success: function (response) {
console.log('Success Login');
},
error: function (request, error) {
console.log('Error Login');
},
})
}
if(action == "register"){
return $.ajax({
url: "register.php",
type: "post",
data: {password: password},
beforeSend: function() {
console.log('beforeSend register');
},
success: function (response) {
console.log('Success Register');
},
error: function (request, error) {
console.log('Error Register');
},
})
}
}
var actions = ['register', 'login'];
services.forEach(checkActions);
function checkActions(item, index) {
if (document.getElementById(item).checked) {
var promise = run_action(item);
promise.success(function (data) {
console.log('Run after');
});
console.log('Run first')
}
}
In this case login and register are both launched at the same time, login doesn't wait for register to finish so he can start processing.
In case you can't properly wait for checkActions from the outside, you could maintain a task queue for that:
let queue = Promise.resolve();
function checkActions(item, index) {
queue = queue
.then(() => run_action(item))
.then(() => {
console.log("Next item was processed", item);
// Your code here
});
// Synchronous code here - This won't execute in order!
}
Currently your code runs through the forEach loop with each action and invokes checkActions with that action, thus firing the request. Array.prototype.forEach executes synchronously (without any kind of check to the promises returned by $.ajax). The following would wait for 'register' to finish before firing 'login':
function checkActions(item) {
if (document.getElementById(item).checked) {
return run_action(item);
}
}
checkActions('register')
.then(data => {
return checkActions('login');
});
I'm not super familiar with jQuery's promise structure, so I used .then, but I believe you can use .success without issue as well.
Unrelated comment, your run_actions function should really be split into two functions (login and register) since they are completely unrelated aside from the fact that they are making requests.
First- its not a good practice to trust a order-based function (AKA - run them by the array order), run your functions according to logic.
For example: if the first function was failed - you dont want to run the next functions in the array.
If you consist to run the functions in array - you can use an async
async function runActions( actionsList ) {
for(const action of actionsList) {
await run_action( action );
}
};
In general - we use the then method to run anther function when specific promise is done. Like so:
promise.then( onSuccess => {
// try to log in
}, onFail => {
// tell the user the signup was failed
});
BTW - you can use the native fetch instade of jQuery ajax, and get simple to use, promise-based way to communicate with your sever.
Like so:
fetch("login.php" , {
method: 'POST', // or 'PUT'
body: {password: password}, // data can be `string` or {object}!
headers:{
'Content-Type': 'application/json'
}
}).then( ... )
I have a function getPackageName, and inside this function i defined a promise , i need to save the value of this promise and return the value outside , so whenever i call getPackageName,it will return promise result value ...
getPackageName(modelName){
let modelReq = new Ext.Promise(function(resolve, reject){
Ext.Ajax.request({
url: `db/code/pkgname?tablename=${modelName}`,
method: 'GET',
callback: function(options, success, response){
if (success){
if (response){
resolve(response);
}
else{
console.log("No response from server");
}
}
});
});
modelReq.then(res){
return res.res
}
}
it's not working as expected , and whenever i call getPackageName, it will return undefined .
Any help would be appreciated for sure .
I am looping through a map, where I want to make a separate AJAX call with each map value as parameter, to fetch some data and log it. See below. This is working, but I'd like to have the AJAX calls go in order of the map. Because each call is asynchronous, so seems like I should use promises to achieve execution in order. But I am new to promises and don't really know how to do it here. I have look elsewhere on here but could not find anything. Please help.
map.forEach(function(url, key) {
log(url);
});
function log(url) {
$.ajax({
url: url,
dataType: 'json',
success: function (result) {
console.log(result.value);
console.log(result.name);
console.log(result.action);
}
});
}
Since $.ajax returns a promise, you can use promise chaining to achieve what you want
var p = $.when();
map.forEach(function(url, key) {
p = p.then(function() {
return log(url);
});
});
function log(url) {
return $.ajax({
url: url,
dataType: 'json',
success: function (result) {
console.log(result.value);
console.log(result.name);
console.log(result.action);
}
});
}
Note: the code above uses only jQuery, no native promises
Or using reduce function of Array
map.reduce(function(p, url) {
return p.then(function() {
return log(url);
});
}, $.when());
If you can use ES2015+, so have native Promises,
map.reduce((p, url) => p.then(() => log(url)), Promise.resolve());
If you wanted, you can also do it like this
function log(url) {
return $.ajax({
url: url,
dataType: 'json'
});
}
map.reduce((p, url) => p.then(results => log(url).then(result => results.concat(result))), Promise.resolve([]))
.then(results => {
results.forEach(result => {
console.log(result.value);
console.log(result.name);
console.log(result.action);
})
});
The difference being as that all the console.log's would happen once the LAST request finished (and if any fail, none of the console log's would happen)
If you could use async/await syntax in your project, then nothing could be easier:
async function log(url) {
return await
$.ajax({
url: url,
dataType: 'json',
})
.then(function(result) {
console.log(result.value);
console.log(result.name);
console.log(result.action);
});
}
async function run() {
for (var i = 0; i < map.length; i++) {
await log(map[i]);
}
}
run();
You see, I changed forEach to for loop. It's important for await usage, because it provides (instead of forEach and other callback based loops) synchronicity of async log calls.
UPD Here is the Plunker which demonstrates such an approach.
To chain promises should work:
function ajaxPromises(urls) {
return Promise.all(urls.map(function(url) {
return $.ajax({
url: url,
dataType: 'json'
})
}))
}
Usage:
ajaxPromises(['http://yoururl.com','http://yoururl.com'])
.then(function (result) {
// do something with result
})
.catch(function (error) {
// do something with error
})
I'd like in the first function to get response from api and put it into the object field and then in the second function log it.
App starts, when we call init function - initApp(), which describes the same order: first get data, then log it.
class App {
constructor() {
this.data;
}
// init app
initApp() {
this.getServerData();
this.foo();
}
// get data using ajax
getServerData() {
$.ajax({
url: 'https://jsonplaceholder.typicode.com' + '/posts/1',
method: 'GET',
dataType: 'json',
})
.then(data => {
// putting data to object field
this.data = data;
})
.catch(error => {
console.log(error);
});
}
// log it
foo() {
console.log('another function in action, api response:');
console.log(this.data);
}
}
const app = new App();
app.initApp();
But the field app.data is undefined, cause foo() runs before getData() ends.
It's probably to solve adding setTimeot() to initApp()
// init app
initApp() {
this.getData();
setTimeout(() => {
this.foo();
},
1000
);
}
Is it normal or it would be better to use other cases?
Problem is that in my real app besides one foo() will be another 5-7 functions. And put all of them into .then ?
Maybe there are other solutions?
Any help will be highly appreciated.
You need to use callback here.
// init app
var self=this;
initApp() {
this.getServerData(function(){ self.foo(); });
}
// get data using ajax
getServerData(callback) {
$.ajax({
url: 'https://jsonplaceholder.typicode.com' + '/posts/1',
method: 'GET',
dataType: 'json',
})
.then(data => {
// putting data to object field
this.data = data;
callback() ;
})
.catch(error => {
console.log(error);
});
}
call foo() from response of ajax call, this will make sure that foo will be executed only after ajax call.
I know you can't make an asynchronous function behave synchronously but
how do I add some kind of order to my promises chain?
One result relies on the previous promise value and when that doesn't happen I get an undefined error. It's an http request so it is relying on external factors like how fast my connection can execute the request, etc.
module.exports.movieCheck = function(authToken) {
return request({
method : 'GET',
uri : 'https://graph.facebook.com/' + profileID + '/posts?fields=message&limit=25&' + authToken
}).spread(function (response, body) {
console.log('https://graph.facebook.com/' + profileID + '/posts?fields=message&limit=25&' + authToken);
return body;
}, function(e) {
console.log(e);
});
};
I am calling the above method as follows. However console.log returns undefined.
movieCheck.getToken()
.then(function(token) {
movieCheck.movieCheck(token);
})
.then(function(movies) {
console.log(movies); //should print json data
});
Terminal prints
undefined
https://graph.facebook.com/.../posts?fields=message&limit=25&access_token=....
Try to return the promise from the first then callback
movieCheck.getToken()
.then(function (token) {
return movieCheck.movieCheck(token);
}).then(function (movies) {
console.log(movies); //should print json data
});