I have a code that searches for some data in memory storage and if not found searches that data on server and caches it in memory.
How can I return an object as a Promise so that the caller can just invoke a "done" on it?
The code looks like that:
if (foundInLocalStorage)
{
// This part I cannot make to work, caller does not have its 'done' fired
var defered = $.Deferred();
defered.resolve();
defered.promise(dataFound);
}
else
{
return $.ajax
(
{
url: someUrl,
dataType: 'json',
data: { id: 101 }
}
)
.done
(
//That part is fine
......
);
}
You need to return a promise
if (foundInLocalStorage) {
var defered = $.Deferred();
defered.resolve(dataFound);//resolve the promise with the data found
//or setTimeout(defered.resolve.bind(promise, 5)); if you want to maintain the async nature
return defered.promise();//return a promise
} else {
return $.ajax({
url: someUrl,
dataType: 'json',
data: {
id: 101
}
}).done(
//That part is fine
......
);
}
Related
I'm struggling to implement deferred to get async ajax response. I have this setup:
report.js
function getReport(ref)
{
$.ajax({
url: "report.php",
dataType: 'json',
data: {
ref: ref,
},
success: function(result){
return (result);
}
}
});
}
index.html
<script>
function firstFunction() {
console.log ("start");
getReport(2, 'queue', 'hour', '2018-09-09', '2018-09-10', 'pageviews', 'page', 's1390_5bbb4639ff37');
};
var test = firstFunction();
alert(test);
</script>
Currently I get "undefined" returned straight away because the alert box doesn't wait for the ajax function to run. Using some tutorials online i've tried to implement it this way:
report.js
function getReport(ref)
{
var deferred = $.Deferred();
$.ajax({
url: "report.php",
dataType: 'json',
data: {
ref: ref,
},
success: function(result){
deferred.resolve(result);
}
}
});
returned deferred.promise();
}
index.html
<script>
function firstFunction() {
console.log ("start");
getReport(2, 'queue', 'hour', '2018-09-09', '2018-09-10', 'pageviews', 'page', 's1390_5bbb4639ff37');
};
$.when(getData()).done(function(value) {
alert(value);
});
getData().then(function(value) {
alert(value);
});
</script>
I've obviously made a few mistakes on the way because I'm getting the errors below and I can't seem to get past it:
Uncaught SyntaxError: Unexpected identifier
index2.html:12 start
index2.html:13 Uncaught ReferenceError: getReport is not defined
at firstFunction (index2.html:13)
at index2.html:16
I think the addition of the deferred object in getReport is unnecessary because $.ajax already creates one for you. It might be better to modify your original code this way:
function getReport(ref)
{
return $.ajax({ // Return the deferred object here. It is returned by .ajax()
url: "report.php",
dataType: 'json',
data: {
ref: ref,
} // Remove the callback here.
// You cannot call return in the way you're trying here.
// The context is different and outside of normal flow.
});
}
then in your index file:
<script>
function firstFunction() {
console.log ("start");
// You must return the returned value here as well, otherwise variable `test` is going to be undefined.
return getReport(2, 'queue', 'hour', '2018-09-09', '2018-09-10', 'pageviews', 'page', 's1390_5bbb4639ff37');
};
var test = firstFunction(); // test is now a deferred object
test.done(function(data) {
alert(data);
});
</script>
I'm pretty new to Javascript. Please don't make it too harsh :)
I have two functions, both of which involve executing jQuery requests within for loops. For example,
function a(n,locations) {
for (var i = 0; i < n; i ++) {
$.ajax({
url: 'https://geocoder.cit.api.here.com/6.2/geocode.json',
type: 'GET',
dataType: 'jsonp',
jsonp: 'jsoncallback',
data: {
searchtext: input,
app_id: APP_ID,
app_code: APP_CODE,
},
success: function (data) {
handleData(data,locations);
}
});
}
The handleData() function would make changes to the empty array locations from the jQuery data. My function b(m) is of similar format but would use the updated locations as input.
Now, I have a c(n,m) in which I would like execute a() and b() sequentially:
function c(n,m) {
var locations = [];
a(n,locations);
b(m,locations);
}
From previous answers I understand that sequentially executing functions involving jQuery calls can be achieved by using promises (such as .then). However, this solution is only applicable when a(n) returns a promise, which is not achievable under the for-loop structure. Could you please share your insights on how to solve this issue? Thanks in advance for the help.
I would suggest recursion instead of your for loop. For example, you can call the function recursionExample like this,
function a(n) {
return new Promise ((resolve, reject) {
(function recursionExample(a) {
if (a === n) {
resolve;
} else {
$.ajax({ url: 'https://geocoder.cit.api.here.com/6.2/geocode.json',
type: 'GET',
dataType: 'jsonp',
jsonp: 'jsoncallback',
data: {
searchtext: input,
app_id: APP_ID,
app_code: APP_CODE,
},
success: function(data) {
handleData(data);
recursionExample(a + 1);
}
});
}
})(0);
});
}
This will then allow you to use the promise and .then functions. Like so...
function c(n,m) {
var locations = [];
a(n,locations)
.then (function() {
b(m,locations);
});
}
I'm new in FLUX and I have problem how to handle ajax in FLUX.
My situation is following :
I have file commentAPI.js
//all js files are compiled from coffescript
// fetching all comments from server
_fetchComments: function() {
var promise;
promise = $.ajax({
url: "comments/show",
type: "GET",
dataType: "json"
});
return promise.then(function(response) {
// here should be any action ?
}, function(error) {
return console.log(error);
}); }
Then I have commentActions.js
fetchComments: function () {
allcomments=commentAPI._fetchComments();
return Dispatcher.dispatch({
actionType: ActionTypes.ALL_COMMENTS,
comments: allcomments
});
}
This code actually doesnt work because function _fetchComments called in commentActions.js return whole promise.
What I want to do: I would like to get response from ajax callback function and pass the result to my payload object and then dispatch it by Dispatcher in my _fetchComments() function in commentActions.js
How is the best way to do it? How can I get the access to the ajax callback function response ?
You should dispatch _fetchComments function and when that promise is resolved, invoke the action fetchComments.
In the react code you should invoke the async function (i.e. _fetchComments).
In your example:
// fetching all comments from server
_fetchComments: function() {
var promise;
promise = $.ajax({
url: "comments/show",
type: "GET",
dataType: "json"
});
return promise.then(function(response) {
// put the sync action here
fetchComments(response)
}, function(error) {
return console.log(error);
}); }
And don't forget to remove it from the action (i.e fetchComments)
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
});
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.