Right now I have funcA, funcB, arrayA and arrayB. In funcA, arrayB will populate itself by requesting some external information and the time for doing this is varied. I want it to execute funcB after arrayB.length == arrayA.length, and arrayB is a global variable that its content will be used in funcB. I assume that I need to use JQuery deferred and promise..so I tried this
var arrayB = [];
var hi = funcA();
hi.then(funcB());
funcA(){
var Dfd = $.Deferred();
arrayB.forEach(function(x, i){
some external retrieval;
if (arrayB.length == arrayA.length){
Dfd.resolve(arrayB);
}
})
return Dfd;
}
But this doesn't help. How should I change it?
arrayB.forEach won't do a thing. It's empty. Forget all this functions and deferred.
fetch('/mydata.json')
.then(function(response) {
//save your data from response to arrayB
//call your funcA
})
.catch((error) => {
console.log(error);
});
I don't know why you needed that:
if (arrayB.length == arrayA.length){
Dfd.resolve(arrayB);
}
But feel free to make a check before calling funcA.
I resolved the problem by doing this:
hi.done(function(){funcA()});
Related
function getHiddenTable(){
var url = ".......";
var apptoken = "blahblah";
return $.get(url, {
act: "API_DoQuery",
clist: "7.8.6",
data: apptoken
});
}
function getRprTable(){
var url = "........";
var apptoken = "blahblah";
return $.get(url, {
act: "API_DoQuery",
clist: "3.60",
data: apptoken
});
}
function main(){
getHiddenTable().then(function(xml_hidden){
hiddenTable = xml_hidden;
console.dirxml(hiddenTable);
return getRprTable();
}).then(function(xml_rpr){
rprTable = xml_rpr;
console.dirxml(rprTable);
});
}
main();
getHiddenTable() returns a $.get request and getRprTable() also returns a $.get request
Both of these functions return two separate xml files that contain different data. I assign both xml files to two separate global variables so they have scope to other function that I need to use them in. However, both console statements display the initial request from getHiddenTable(). But why? And what can I do to fix this?
Update
Hey guys, thanks for the help. I found out my problem with much frustration and actually utilized $.when, from the person who provided the idea in the comments.
$.when(getHiddenTable(), getRprTable()).done(function(xml_hidden, xml_rpr){
console.dirxml(xml_hidden[0]);
console.dirxml(xml_rpr[0]);
});
Accessing the data value of the callback function objects can be done by simply accessing the 0th index.
Thanks
You'll likely want to use Promise.all() to run multiple promises at once and return the results of all the promises once they have all finished.
Example:
Promise.all([getHiddenTable(), getRprTable()])
.then(function(results) {
let hiddenTable = results[0];
let rprTable = results[1];
// do stuff with your results
});
Hope that helps
The response received is always an empty array. The inner stands_query in the for loop never gets executed. Also I would like to know if there is again an inner query inside the stands query then how do I achieve that.
STANDS CLASS STADIUMS CLASS Code below :
var final_list = [];
query.find().then(function(stadiums){
_.each(stadiums,function(stadium){
var stands_query = new Parse.Query(“Stands");
stands_query.equalTo(“stdId”,stadium.get(“stdId"));
var promise = stands_query.find().then(function(stands){
_.each(stands,function(stand){
var jsonObject = {
“stdId": stand.get(“stdId").id,
}
final_list.push(jsonObject);
});
return null;
},function(error){
return response.error(error);
});
return promise;
});
}).then(function(){
response.success(final_list);
});
Your first .then isn't returning anything. I'll break your code down so you can see it:
query.find().then(function(stadiums){ //anonymous function 1
_.each(stadiums,function(stadium){ //anonymous function 2
return "foo" //this returns "foo" as a result of anonymous function 2.
});
//Nothing explicitly returned from function 1!
}).then(function(){
response.success(final_list);
});
A function that lacks an explicit return statement will return undefined. Your code then executes "response.success" before any of the internal promises resolve.
What you could do instead is create an array of internal promises that you wait for with Parse.Promise.when:
query.find().then(function(stadiums){
var promises = [];
_.each(stadiums,function(stadium){
var promise = stands_query.find().then(...)
promises.push(promise);
});
//if returning another promise, the ".then" won't execute until it completes.
return Parse.Promise.when(promises);
}).then(function(){
response.success(final_list);
});
All this being said, you may run into timeout issues depending on how large your dataset is. Consider rewriting your query so that you query for Stands belonging to a Stadium with relational queries instead.
Update
Now that you've updated your question with fields, it looks like your line stands_query.equalTo(“stdId”,stadium.get(“stdId")); has two mistakes and will never return results. It should be stands_query.equalTo(“stadiumId”,stadium);.
We have many Stadiums, and every stadium has many Stands. The relationship between Stadium and Stand is represented in data by a pointer column on the Stands class called "stadiumId".
In comments, the functional goal is stated very simply: a JSON array of stands. This requires a single query, no looping at all:
function allTheStands() {
var query = new Parse.Query("Stands");
query.include("stadiumId");
return query.find().then(function(stands) {
return JSON.stringify(stands);
});
}
// call it like this:
allTheStands().then(function(jsonStands) {
// jsonStands is all of the stands represented as son
});
EDIT
A more roundabout way to the same result is to not include stadiumId in the query, instead doing a fetch after the stands query completes.
(This is just a specific form of advice given by #adamdport, given details of your data. You should credit his answer if you find this useful).
// adding underscorejs for handling arrays and other utils
var _ = require('underscore');
function allTheStands() {
var stands;
var query = new Parse.Query("Stands");
return query.find().then(function(result) {
stands = result;
// we're not done yet, because we need to fetch each stand's stadium
var promises = _.map(stands, function(stand) {
return stand.get("stadiumId").fetch().then(function(stadium) {
stand.set("stadiumId", stadium);
});
});
// as adamdport suggests, the crux of the looping answer is to use Promise.when()
return Parse.Promise.when(promises);
}).then(function() {
return JSON.stringify(stands);
});
}
I'm new on AngularJS and JavaScript.
I am getting remote information for each of the elements of an array (cars) and creating a new array (interested prospects). So I need to sync the requests. I need the responses of each request to be added in the new array in the same order of the cars.
I did it first in with a for:
for (a in cars) {
//async request
.then(function () {
//update the new array
});
}
This make all the requests but naturally didn't update the new array.
After seeking in forums, I found this great examples and explanations for returning a intermediate promise and sync all of them.
1. http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html
2. http://stackoverflow.com/questions/25605215/return-a-promise-from-inside-a-for-loop
3. http://www.html5rocks.com/en/tutorials/es6/promises/
(#MaurizioIndenmark, #Mark Rajcok , #Michelle Tilley, #Nolan Lawson)
I couldn't use the Promise.resolve() suggested in the second reference. So I had used $q.defer() and resolve(). I guess I have to inject a dependency or something else that I missed. As shown below:
In the Controller I have:
$scope.interestedProspects = [] ;
RequestDetailsOfAsync = function ($scope) {
var deferred = $q.defer();
var id = carLists.map(function (car) {
return car.id;
}).reduce(function (previousValue, currentValue) {
return previousValue.then(function () {
TheService.AsyncRequest(currentValue).then(function (rData) {
$scope.interestedProspects.push(rData);
});
});
}, deferred.resolve());
};
In the Service I have something like:
angular.module('app', []).factory('TheService', function ($http) {
return {
AsyncRequest = function (keyID) {
var deferred = $q.defer();
var promise = authorized.get("somep.provider.api/theService.json?" + keyID).done(function (data) {
deferred.resolve(data);
}).fail(function (err) {
deferred.reject(err);
});
return deferred.promise;
}
}
}
The displayed error I got: Uncaught TypeError: previousValue.then is not a function
I made a jsfiddle reusing others available, so that it could be easier to solve this http://jsfiddle.net/alisatest/pf31g36y/3/. How to wait for AsyncRequests for each element from an array using reduce and promises
I don't know if the mistakes are:
the place where the resolve is placed in the controller function.
the way the reduce function is used
The previousValue and currentValue sometimes are seen by javascript like type of Promise initially and then as a number. In the jsfiddle I have a working example of the use of the reduce and an http request for the example.
Look at this pattern for what you want to do:
cars.reduce(function(promise, car) {
return promise.then(function(){
return TheService.AsyncRequest(car).then(function (rData) {
$scope.details.push(rData);
});
});
}, $q.when());
This will do all the asynchronous calls for every car exactly in the sequence they are in the cars array. $q.all may also be sufficient if the order the async calls are made doesn't matter.
It seems you are calling reduce on an array of ids, but assume in the passed function that you are dealing with promises.
In general, when you want to sync a set of promises, you can use $q.all
You pass an array of promises and get another promise in return that will be resolved with an array of results.
I understand using promises in simple scenarios but currently really confused on how to implement something when using a for loop and some updates to local sqlite database.
Code is as follows
surveyDataLayer.getSurveysToUpload().then(function(surveys) {
var q = $q.defer();
for (var item in surveys) {
var survey = surveys[item];
// created as a closure so i can pass in the current item due to async process
(function(survey) {
ajaxserviceAPI.postSurvey(survey).then(function(response) {
//from response update local database
surveyDataLayer.setLocalSurveyServerId(survey, response.result).then(function() {
q.resolve; // resolve promise - tried only doing this when last record also
})
});
})(survey) //pass in current survey used to pass in item into closure
}
return q.promise;
}).then(function() {
alert('Done'); // This never gets run
});
Any help or assistance would be appreciated. I'm probably struggling on how best to do async calls within loop which does another async call to update and then continue once completed.
at least promises have got me out of callback hell.
Cheers
This answer will get you laid at JS conferences (no guarantees though)
surveyDataLayer.getSurveysToUpload().then(function(surveys) {
return Promise.all(Object.keys(surveys).map(function(key) {
var survey = surveys[key];
return ajaxserviceAPI.postSurvey(survey).then(function(response){
return surveyDataLayer.setLocalSurveyServerId(survey, response.result);
});
}));
}).then(function() {
alert('Done');
});
This should work (explanations in comments):
surveyDataLayer.getSurveysToUpload().then(function(surveys) {
// array to store promises
var promises = [];
for (var item in surveys) {
var survey = surveys[item];
// created as a closure so i can pass in the current item due to async process
(function(survey) {
var promise = ajaxserviceAPI.postSurvey(survey).then(function(response){
//returning this promise (I hope it's a promise) will replace the promise created by *then*
return surveyDataLayer.setLocalSurveyServerId(survey, response.result);
});
promises.push(promise);
})(survey); //pass in current survey used to pass in item into closure
}
// wait for all promises to resolve. If one fails nothing resolves.
return $q.all(promises);
}).then(function() {
alert('Done');
});
Awesome tutorial: http://ponyfoo.com/articles/es6-promises-in-depth
You basically want to wait for all of them to finish before resolving getSurveysToUpload, yes? In that case, you can return $q.all() in your getSurveysToUpload().then()
For example (not guaranteed working code, but you should get an idea):
surveyDataLayer.getSurveysToUpload().then(function(surveys) {
var promises = [];
// This type of loop will not work in older IEs, if that's of any consideration to you
for (var item in surveys) {
var survey = surveys[item];
promises.push(ajaxserviceAPI.postSurvey(survey));
}
var allPromise = $q.all(promises)
.then(function(responses) {
// Again, we want to wait for the completion of all setLocalSurveyServerId calls
var promises = [];
for (var index = 0; index < responses.length; index++) {
var response = responses[index];
promises.push(surveyDataLayer.setLocalSurveyServerId(survey, response.result));
}
return $q.all(promises);
});
return allPromise;
}).then(function() {
alert('Done'); // This never gets run
});
Hi I am struggling to understand Angular deffering and promises.
I would like to know when all promises have been completed so i can hide a "loading" message.
So here is my code example:
$scope.buildTeam = function () {
$scope.Message = "loading...";
var deferred = $q.defer();
var promiseList = [];
c = $scope.teamModels[0];
for (index = 0; index < c.quantity; ++index) {
var assignment = new teamAssignment(c.assignmentTypeId, $scope.parentAssignment.AssignmentId, c.description);
promiseList.push(departmentService.addAssignment(assignment).then(function (result) {
//added lead/captain. Now insert visually on page
insertToScope($scope, result);
}));
}
}
$q.all(promiseList).then(function () {
deferred.resolve();
$scope.Message = "Loaded.";
});
}
The problem is Have is that $scope.Message shows "Loaded" well before the data has been inserted onto the page in the case of a large data pull.
Could it be that i also need to defer insertToScope?
InsertToScope simply reads:
function insertToScope($scope, a) {
//get root scope
var rs = angular.element("#ngRootContainer").scope();
rs.parentAssig.push(a);
}
And the department service looks like this:
departmentModule.factory('departmentService', function ($http, $q) {
return {
addAssignment: function(assignment){
var deferred = $q.defer();
$http.post('/Department/addAssignmentReturnAssignmentRow', assignment).success(deferred.resolve).error(deferred.reject);
return deferred.promise;
}
});
So my question is, what do i need to do to call a function only after all the promises are done?
Thank you in advance for your feedback.
$q.all should do what you need. If your code doesn't work, I see two options:
You pass in a promiseList that does not contain all promises you want to wait for. Debug your code and check that all promises are passed in. Make sure it's an array you pass as the first parameter.
The promises you pass in resolve before you expect them to resolve. If you log 'A' in insertToScope, and 'B' in the then of your $q.all, you should see
A
...
A
B
in the console.
Here is a simple plunkr that shows how to use $q.all(): http://plnkr.co/edit/9QH9Y0w7DG0WCouMuX82?p=preview