This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 7 years ago.
I call a function which registers a registrationId is issued using chrome.gcm. Everything is fine but because the callback takes time, my code does not work without a console.log or alert. Any tips how I can make it wait?
var registrationId = ""
function register() {
var senderId = 'MY_SENDER_ID';
chrome.gcm.register([senderId], registerCallback);
}
function registerCallback(regId) {
registrationId = regId;
if (chrome.runtime.lastError) {
return false;
}
chrome.storage.local.set({registered: true});
}
$(function(){
$("#register-form").submit(function(e) {
//Disable from further calls
$('#submit').disabled = true;
register()
var name = $('#name').val()
var email = $('#email').val()
//Insert console.log or alert here to slow it down
var chromeId = registrationId
$.ajax({
type: "POST",
url: 'MY_URL',
ajax:false,
data: {chromeId: chromeId, name: name, email:email},
success: function(result)
{
console.log(result)
}
});
});
})
You need to execute the method as part of the callback, since the value that needs to be passed in as part of your AJAX request, is available only after ASYNC process completes.
You can use a Deferred objects in such cases. As soon as the it is resolved you can execute your AJAX call.
$(function() {
$("#register-form").submit(function(e) {
//Disable from further calls
$('#submit').disabled = true;
var senderId = 'MY_SENDER_ID';
// Store the promise in a variable
var complete = chrome.gcm.register([senderId]);
// When resolved it will, hit the callback
// where you have access to the value
// which is then passed to your AJAX request
$.when(complete).done(function(regId) {
var registrationId = regId;
if (chrome.runtime.lastError) {
return false;
}
chrome.storage.local.set({
registered: true
});
$.ajax({
type: "POST",
url: 'MY_URL',
ajax: false,
data: {
chromeId: registrationId,
name: name,
email: email
},
success: function(result) {
console.log(result)
}
});
});
});
});
The code that comes after register() should go in a new callback which accepts registrationId as a parameter, and is passed to register(). Then, register() can call this callback with the registrationId it gets back from chrome.gcm.register. No need for the global registrationId variable.
function register(callback) {
var senderId = 'MY_SENDER_ID';
chrome.gcm.register([senderId], function (regId) {
if (chrome.runtime.lastError) {
return false;
}
chrome.storage.local.set({registered: true});
callback(regId);
});
}
$(function(){
$("#register-form").submit(function(e) {
//Disable from further calls
$('#submit').disabled = true;
register(function (registrationId) {
var name = $('#name').val()
var email = $('#email').val()
//Insert console.log or alert here to slow it down
var chromeId = registrationId
$.ajax({
type: "POST",
url: 'MY_URL',
ajax:false,
data: {chromeId: chromeId, name: name, email:email},
success: function(result)
{
console.log(result)
}
});
});
});
})
Promises and async/await helps with stuff like this, also.
Related
I have read a lot about promises but I'm still not sure how to implement it.
I wrote the folowing AJAX call with async=false in order for it to work, but I want to replace it with promise as I saw that async=false is deprecated.
self.getBalance = function (order) {
var balance;
$.ajax({
url: "/API/balance/" + order,
type: "GET",
async: false,
success: function (data) {
balance = data;
},
done: function (date) {
}
});
return balance;
}
Would you be able to help me? I just need an example to understand it.
As first point, you don't want to set an asynchronous call to false as it will lock the UI.
You could simplify your method returning the ajax object and the handle it as a promise.
self.getBalance = function (orderNumber) {
return $.ajax({
url: "/Exchange.API/accountInfo/balance/" + orderNumber,
type: "GET",
});
};
var demoNumber = 12;
self.getBalance(demoNumber).then(function(data){
console.log(data);
},function(err){
console.log("An error ocurred");
console.log(err);
});
Return promise object from getBalance method:
self.getBalance = function (orderNumber) {
return $.ajax({
url: "/Exchange.API/accountInfo/balance/" + orderNumber,
type: "GET"
});
}
and use it later like this:
service.getBalance().then(function(balance) {
// use balance here
});
Hi i am using jquery and ajax to retrieve the user id of the logged in user, Im saving this into a variable as I want to be able to do some logic with it later on. however I am having trouble accessing it. My code is below:
$(document).ready(function () {
var taskBoard = {
fetch: function (url, data) {
$('.loading-icon').fadeIn();
$('.task_board').addClass('loading');
$.ajax({
url: url,
async: true,
dataType: 'json',
data: data,
type: 'POST',
success: function (json) {
$('.loading-icon').fadeOut();
$('#task_board').html($(json.data.taskBoard));
$('.task_board').removeClass('loading');
$('.update-results').hide();
} // end success
}); //end ajax
}, //end fetch function
authUser: function (url, data) {
$.ajax({
url: url,
async: true,
dataType: 'json',
data: data,
type: 'POST',
success: function (json) {
$.each($(json), function (index, item) {
taskBoard.storeUser(item.id);
});
} // end success
}); //end ajax
}, //end authUser function
storeUser: function (param) {
var authUserId = param;
return param;
// if I do an alert here the correct user id is returned.
},
} //end var taskBoard
//However if I do an alert here outside of the var taskBoard I get an undefined.
alert(taskBoard.storeUser());
});
Any ideas how I can get this globally assigned variable outside of this function?
change this
storeUser: function (param) {
var authUserId = param;
return param;
// if I do an alert here the correct user id is returned.
},
change to this:
authUserId : null,
storeUser: function (param) {
if (param)
{
this.authUserId = param;
}
return this.authUserId;
},
Now the var authUserId will be stored as a property in the taskBoard object.
When param is undefined it will return the value unupdated if not it will update it first and then returns it.
A more elegant solution would be to use Object.defineProperty here.
Delete the storeUser property and after the declaration of the taskBoard object add this:
Object.defineProperty(taskBoard, "storeUser", {
get : function(){ return this.StoreUserVar; },
set : function(value){ this.StoreUserVar = value; }
});
Now you can assign the userid with:
taskBoard.storeUser = item.id;
//-------- taskBoard object
success: function (json) {
$.each($(json), function (index, item) {
taskBoard.storeUser = item.id;
doOtherFunction();
});
//--------
function doOtherFunction()
{
//the callback function fired from the success.
alert(taskBoard.storeUser); //this will alert with the value set.
}
Well if you need a global variable then declare that variable before the document.ready, since variables defined in this function are only valid in this function
Javascript Scope Examples
Problem: Extracting data from ajax request inside page.evaluate
Description: I usually get variables out of page.evaluate by simply returning them. However, I need to make an ajax request within the context of a page, and then I need to process its result out of the page's context.
The code I'm trying to fix is:
var theOutput = page.evaluate(function () {
return $.ajax({
async: false,
url: 'http://localhost:8080/captcha.php',
data: { filename: 'C:\\wamp\\www\\images\\0.png' },
type: 'post',
success: function (output) {
parsed_output = $.parseHTML(output);
return parsed_output[4].data.trim();
},
});
});
console.log(theOutput);
The variable parsed_output[4].data.trim() is a string. But when I log output I get a [object Object], with the properties abort, always, complete, done, error, fail, getAllResponseHeaders, getResponseHeader, overrideMimeType, pipe null, progress, promise, readyState, setRequestHeader, state, statusCode, success,then.
Question: How can I extract theOutput from page.evaluate?
Since this is a blocking AJAX request, you can create a temporary variable:
var theOutput = page.evaluate(function () {
var result;
$.ajax({
async: false,
...
success: function (output) {
parsed_output = $.parseHTML(output);
result = parsed_output[4].data.trim();
},
});
return result;
});
console.log(theOutput);
You can also directly access the responseText from the jqXHR object:
var theOutput = page.evaluate(function () {
var jqXHR = $.ajax({
async: false,
url: 'http://localhost:8080/captcha.php',
data: { filename: 'C:\\wamp\\www\\images\\0.png' },
type: 'post'
});
parsed_output = $.parseHTML(jqXHR.responseText);
return parsed_output[4].data.trim();
});
console.log(theOutput);
If you fear that async: false is deprecated, you can simply use the underlying XMLHttpRequest to use blocking execution:
var theOutput = page.evaluate(function () {
var request = new XMLHttpRequest();
request.open('POST', 'http://localhost:8080/captcha.php', false);
request.send($.param({ filename: 'C:\\wamp\\www\\images\\0.png' }));
var parsed_output = $.parseHTML(request.responseText);
return parsed_output[4].data.trim();
});
console.log(theOutput);
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 8 years ago.
I have the following function:
function sendDocument( objektnummer, id )
{
var url = $( "#objectdata" ).data( "url-send" );
var data = {};
data["objektnummer"] = objektnummer;
data["id"] = parseInt(id);
var result = false;
$.ajax({
type: "POST",
url: url,
data: data,
dataType: "json"
})
.done(function(resp){
console.log("send ajax was successfull");
result = true;
})
.error(function(resp){
console.log("no connection");
result = false;
});
console.log(result);
return result;
}
in the console I got the positive message "send ajax was successful", but when I print the result on the end of the function to the console, I see that the variable result have the value false.
You cannot return values from a function when the Ajax operation is Asynchronous. That function returns long before the return = true is set. Pass a callback, or return the Ajax object (which is a jQuery promise).
Callback version:
function sendDocument( objektnummer, id, callMeWhenDone )
{
var url = $( "#objectdata" ).data( "url-send" );
var data = {};
data["objektnummer"] = objektnummer;
data["id"] = parseInt(id);
$.ajax({
type: "POST",
url: url,
data: data,
dataType: "json"
})
.done(function(resp){
console.log("send ajax was successfull");
callMeWhenDone(true);
})
.error(function(resp){
console.log("no connection");
callMeWhenDone(false);
});
}
Call with a callback:
sendDocument( objektnummer, id, function(success){
if (success){
// Do this!
}
} );
A promise version in this case would look like:
function sendDocument( objektnummer, id )
{
var url = $( "#objectdata" ).data( "url-send" );
var data = {};
data["objektnummer"] = objektnummer;
data["id"] = parseInt(id);
return $.ajax({
type: "POST",
url: url,
data: data,
dataType: "json"
})
.done(function(resp){
console.log("send ajax was successfull");
})
.error(function(resp){
console.log("no connection");
});
}
And would be called like this:
sendDocument( objektnummer, id ).done(function(){
// Do this!
} ).fail(function(){
// Something went wrong!
});
With promises, you can register for the events any number of times (so it is considered more flexible than callbacks)
I have a method below:
self.getOrAddCache = function (key, objectFactory) {
var data = self.getFromCache(key);
if (!data) {
data = objectFactory();
if (data && data != null)
self.addToCache(key, data);
}
return data;
};
I use like this:
function getCities()
{
var cities = getOrAddCache(CacheKeys.Cities, function() {
var cityArray = new Array();
// get city informations from service
$.ajax({
type: "GET",
async: true,
url: "service/cities",
success: function (response) {
$.each(response, function(index, value) {
cityArray.push({
name: value.name,
id: value.id
});
});
}
});
if (cityArray.length > 0)
return cityArray;
else {
return null;
}
});
return cities;
}
getCities function always return null because getCities not waiting for completion async ajax request.
How can i resolve this problem? (Request must be async)
The best solution for this is to use Deferred objects. Since you require your AJAX call to be asynchronous, you should have your getCities function return a promise to return that data at some point in the future.
Instead of storing the raw data in the cache, you store those promises.
If you request a promise that has already been resolved, that will complete immediately. If there's already a pending request for the cached object, the async AJAX call will be started and all outstanding callbacks waiting for that promise will be started in sequence.
Something like this should work, although this is of course untested, E&OE, etc, etc.
self.getCached = function(key, objectFactory) {
var def = self.getCache(key);
if (!def) {
def = objectFactory.call(self);
self.addToCache(key, def);
}
return def;
}
function getCities() {
return getCached(CacheKeys.Cities, function() {
return $.ajax({
type: 'GET',
url: 'service/cities'
}).pipe(function(response) {
return $.map(response, function(value) {
return { name: value.name, id: value.id };
});
});
});
}
Note the usage of .pipe to post-process the AJAX response into the required format, with the result being another deferred object, where it's actually the latter one that gets stored in your cache.
The usage would now be:
getCities().done(function(cities) {
// use the cities array
});
With a callback:
function getCities(callbackFunction)
{
var cities = getOrAddCache(CacheKeys.Cities, function() {
var cityArray = new Array();
// get city informations from service
$.ajax({
type: "GET",
async: true,
url: "service/cities",
success: function (response) {
$.each(response, function(index, value) {
cityArray.push({
name: value.name,
id: value.id
});
});
callbackFunction(cityArray);
}
});
});
}
getCities(function(cityArray){
// do stuff
});
You can't return the result from a function fetching asynchronously the data.
Change your getCities function to one accepting a callback :
function fetchCities(callback) {
var cities = getOrAddCache(CacheKeys.Cities, function() {
var cityArray = new Array();
// get city informations from service
$.ajax({
type: "GET",
async: true,
url: "service/cities",
success: function (response) {
$.each(response, function(index, value) {
cityArray.push({
name: value.name,
id: value.id
});
});
if (callback) callback(cityArray);
}
});
});
}
And use it like this :
fetchCities(function(cities) {
// use the cities array
});
Note that it's technically possible, using async:true, to make the code wait for the response but don't use it : that's terrible practice and it locks the page until the server answers.
You seem to be contradicting yourself.
Something that is asynchronous, by definition, does not pause the script to wait for the end of it's execution. If it does wait, it cannot be asynchronous.
The best wayto fix this is by adding a callback function in your ajax success function that passes the end result to another function, which handles the rest of the execution.